Objective c 插入NSMutableDictionary时,什么是nil,但不是nil
我在iPhone6、iOS 8.3上遇到了一些奇怪的行为 appVersion是传入的NSString*参数Objective c 插入NSMutableDictionary时,什么是nil,但不是nil,objective-c,xcode6.3,ios8.3,Objective C,Xcode6.3,Ios8.3,我在iPhone6、iOS 8.3上遇到了一些奇怪的行为 appVersion是传入的NSString*参数 NSLog(@"A:%@:%d",appVersion,(int)appVersion.length); if (!appVersion) NSLog(@"a"); if (appVersion == 0) NSLog(@"b"); if (appVersion == nil) NSLog(@"c"); if (appVersion == NU
NSLog(@"A:%@:%d",appVersion,(int)appVersion.length);
if (!appVersion)
NSLog(@"a");
if (appVersion == 0)
NSLog(@"b");
if (appVersion == nil)
NSLog(@"c");
if (appVersion == NULL)
NSLog(@"d");
if (appVersion == Nil)
NSLog(@"e");
if ([appVersion isEqual:[NSNull null]])
NSLog(@"f");
NSString* av = [NSString stringWithFormat:@"%@",appVersion];
if ([av isEqualToString:@"(null)"])
NSLog(@"g");
if (((int)appVersion) == 0)
NSLog(@"h");
if (appVersion) {
NSLog(@"B:%@:%d",appVersion,(int)appVersion);
params[@"appversion"] = appVersion;
}
应用程序的发布版本将返回:
A:(null):0
g
h
B:(null):0
然后崩溃('object不能为nil(key:appversion)')
调试生成将返回:
a
b
c
d
e
g
h
什么是nil,但不是nil?检查[NSNull] NSNull类定义了一个单例对象,用于在禁止将nil作为值的情况下(通常在集合对象(如数组或字典)表示null值
结果看起来很奇怪。有一篇很好的文章;谷歌为克里斯·拉特纳(Swift的首席开发者,所以他应该知道他在说什么)的“每个程序员都应该知道的未定义行为” 看起来,在第一条NSLog语句之后,优化编译器决定appVersion不可能为nil,因为将nil传递给NSLog将是未定义的行为。这就解释了为什么不打印a到e 打印“h”,因为appVersion是一个64位指针,int只有32位,所以将非nil appVersion转换为int的结果可能是零。即使确定appVersion不是零,Optimizer也无法删除该检查
因为编译器确定appVersion不是nil,最后一个测试没有完成,appVersion被存储到param中,因为它是nil,所以崩溃 我正在处理一些遗留代码,没有注意到.h和.m文件之间的方法签名有差异 .h文件具有:
- (void) verifyWinner:(NSString*)baseAcctId
appVersion:(NSString*)appVersion
onComplete:(OnCompleteWinnerVerifier)onComplete __attribute__((nonnull));
我猜最初的开发人员希望防止onComplete被设置为nil。但是,由于某些原因,\uuuuu属性((非空))
与每个参数相关联
由于\uuuu属性\uuuu
标记,XCode正在优化所有的!=nil检查发布版本,导致崩溃
这个问题直到现在才在XCode 6.3中出现。因此,也许苹果最近添加了优化,或者在6.3中引入了一个bug,该bug将
\uuuuuu属性\uuuuuuuu>与每个参数关联,而不仅仅是它旁边的参数(出于优化目的)。如何为appVersion???@BC uDilum分配值,它正在从couchbase文档返回的NSDictionary中提取。您也可以添加该代码吗?@Cristik它在某种程度上是一个iOS应用程序,但appVersion没有重置;它已经是0的某个版本了,很难想象有另一个线程100%地正好在if和set之间运行。LogappVersion class
NSNull是我上面的“f”检查。在这两个版本中,它都返回NO。很抱歉,遗漏了。。。根据苹果公司的说法,尝试使用==,这会有所不同:“NSNull实例在语义上等同于nil,但也要注意它不等于nil。要测试null对象值,因此必须进行直接对象比较。”给出编译时警告:比较不同的指针类型('NSString*'和'NSNull*')好的,我将字符串转换为id,但它仍然返回NO。如果在log语句中放置断点,如果打印变量,您会得到什么样的信息?我实际上刚刚意识到它不能是[NSNull-null],因为在插入字典时这不会给您带来问题。但是将nil传递给NSLog是有定义的。它只是显示为0到t他给了一个格式说明符。好的,我算出了。我很快会给出一个答案。但是,这是正确的路径。很好。因此,如果一个参数被声明为非null,你甚至不能在运行时检查它,因为检查被优化编译器删除。换句话说,将nil传递给一个非null参数是未定义的行为。@gnasher729是的,如果它的与每个参数相关联,这可能会导致很多问题。我可能应该提交一份错误报告。很好的发现。一定要发送一份错误报告,其中包含一段简单的可复制代码来演示问题。我认为这都是有意为之的行为。请查看这篇相关文章。特别是,他指出show的意思是“所有指针参数都不能为null”,这是多么令人困惑。他还提到clang最近“开始考虑违反_属性_((非null))契约是未定义的行为”这就解释了为什么你现在看到这个。@JesseRusak是的,我认为你是对的。我只是发现语法中包含了参数号。所以,在这种情况下,它应该被定义为uuu属性uuu((非空(3)))。