NSString 类型的属性何时为 [NSNull null]

Posted

技术标签:

【中文标题】NSString 类型的属性何时为 [NSNull null]【英文标题】:When if ever will a property of type NSString be [NSNull null] 【发布时间】:2012-06-21 10:37:56 【问题描述】:

我正在解析一些 json 以返回基本字符串标记或错误消息。

- (void)callBackWithVerifyHttpResponse:(NSData *)response

    SomeResult *result = [self.parser parseVerifyHttpResponseAndReturnResult:response];
    if (result.token)  [self.delegate callBackWithToken:result.token]; 
    if (result.error)  [self.delegate callBackWithError:result.error]; 

证明这一点的测试

- (void)testVerifyCallbackInvokesErrorCallbackOnDelegateWhenParserReturnsError

    SomeResult *result = [[SomeResult alloc] init];
    result.error = @"fail";
    [[self.delegate expect] callBackWithError:@"fail"];
    [[self.delegate reject] callBackWithToken:OCMArg.any];
    [[[self.parser stub] andReturn:result] parseVerifyHttpResponseAndReturnResult:nil];
    [self.sut callBackWithVerifyHttpResponse:nil];
    [self.delegate verify];


- (void)testVerifyCallbackInvokesTokenCallbackOnDelegateWhenParserReturnsToken

    SomeResult *result = [[SomeResult alloc] init];
    result.token = @"token";
    [[self.delegate expect] callBackWithToken:@"token"];
    [[self.delegate reject] callBackWithError:OCMArg.any];
    [[[self.parser stub] andReturn:result] parseVerifyHttpResponseAndReturnResult:nil];
    [self.sut callBackWithVerifyHttpResponse:nil];
    [self.delegate verify];

一切都很好,直到我将它连接到一个实际的端点 - 只是发现除非我像下面这样修改回调 - 它正在调用两个回调(不是我希望的)

- (void)callBackWithVerifyHttpResponse:(NSData *)response

    SomeResult *result = [self.parser parseVerifyHttpResponseAndReturnResult:response];
    if (result.token != [NSNull null])  [self.delegate callBackWithToken:result.token]; 
    if (result.error != [NSNull null])  [self.delegate callBackWithError:result.error]; 

所以两部分的问题

    为什么我不能写一个测试来证明这一点?每当我将错误或令牌设置为 NULL 或 NSNull 时,它都可以正常工作(但生产工作需要此代码)

    为什么如果我输入!= [NSNull null],生产代码只会在条件条件下失败(但当我在模拟器中运行时,我对值进行NSLog 记录时,除了<null>,我似乎什么也得不到?

请记住,SomeResult 对象上的令牌/错误属性如下所示

@interface SomeResult : NSObject

@property (strong, nonatomic) NSString *token;
@property (strong, nonatomic) NSString *error;

@end

【问题讨论】:

【参考方案1】:

您的原始代码和测试期望令牌或错误是nil,而不是[NSNull null]。大概当您针对生产端点运行它时,您的解析器会将值设置为[NSNull null]

这些测试应该与您修改的代码一起通过:

- (void)testVerifyCallbackInvokesErrorCallbackOnDelegateWhenParserReturnsError

    SomeResult *result = [[SomeResult alloc] init];
    result.error = @"fail";
    result.token = [NSNull null];
    [[self.delegate expect] callBackWithError:@"fail"];
    [[self.delegate reject] callBackWithToken:OCMArg.any];
    [[[self.parser stub] andReturn:result] parseVerifyHttpResponseAndReturnResult:nil];
    [self.sut callBackWithVerifyHttpResponse:nil];
    [self.delegate verify];


- (void)testVerifyCallbackInvokesTokenCallbackOnDelegateWhenParserReturnsToken

    SomeResult *result = [[SomeResult alloc] init];
    result.token = @"token";
    result.error = [NSNull null];
    [[self.delegate expect] callBackWithToken:@"token"];
    [[self.delegate reject] callBackWithError:OCMArg.any];
    [[[self.parser stub] andReturn:result] parseVerifyHttpResponseAndReturnResult:nil];
    [self.sut callBackWithVerifyHttpResponse:nil];
    [self.delegate verify];

当您处理可能会微妙地改变其行为的 Web 服务和/或第三方解析器时,最好进行防御性编码。你可以同时处理nilNSNull

- (void)callBackWithVerifyHttpResponse:(NSData *)response

    SomeResult *result = [self.parser parseVerifyHttpResponseAndReturnResult:response];
    if (result.token && result.token != [NSNull null])  [self.delegate callBackWithToken:result.token]; 
    if (result.error && result.error != [NSNull null])  [self.delegate callBackWithError:result.error]; 

您可能还希望将此设置为 if/else - 要么首先测试错误,如果有错误则永远不要设置令牌,或者如果你得到一个令牌则忽略错误。如果您不想同时调用这两个回调,请在您的代码路径中使其成为不可能。

【讨论】:

以上是关于NSString 类型的属性何时为 [NSNull null]的主要内容,如果未能解决你的问题,请参考以下文章

解决因为NSNull类型导致出现的unrecognized selector sent to instance问题

iOS 中nil,Nil,NULL,NSNull的区别

swift 怎么判读一个字符串为nsnull

nilNilNULL和NSNull学习

无法将“NSNull”类型的值转换为预期的参数类型

nil/Nil/NULL/NSNull区别