我在iPhone 6,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 == 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
然后崩溃('对象不能为nil(key:appversion)')。
调试版本返回:
a
b
c
d
e
g
h
什么是零,但不是零?
答案 0 :(得分:3)
我正在处理一些遗留代码,并没有注意到.h和.m文件之间的方法签名存在差异。
.h文件有:
- (void) verifyWinner:(NSString*)baseAcctId
appVersion:(NSString*)appVersion
onComplete:(OnCompleteWinnerVerifier)onComplete __attribute__((nonnull));
我猜测原始开发人员希望阻止onComplete设置为nil。但是,出于某种原因,__attribute__((nonnull))
与每个参数相关联。
由于__attribute__
标记,XCode正在优化所有发布版本的!= nil检查,导致崩溃。
此问题现在才出现在XCode 6.3中。所以,也许Apple最近添加了优化,或者引入了6.3中的一个错误,它将__attribute__
与每个参数相关联,而不仅仅是它旁边的参数(无论如何都是为了优化目的)。
答案 1 :(得分:0)
检查[NSNull null]
NSNull类定义了一个单例对象,用于在禁止nil作为值的情况下表示空值(通常在集合对象(如数组或字典)中)。
答案 2 :(得分:0)
结果看起来很奇怪。这篇文章不错; google for"每个程序员应该知道未定义的行为"作者:Chris Lattner(Swift的首席开发人员,所以他应该知道他在说什么)。
看起来在第一个NSLog语句之后,优化编译器决定appVersion不可能是nil,因为将nil传递给NSLog将是未定义的行为。这解释了为什么不打印a到e。
" H"打印,因为appVersion是一个64位指针,int只有32位,所以将非零appVersion转换为int只是可能的结果为零。即使确定appVersion不是零,Optimiser也无法删除该检查。
因为编译器确定appVersion不是nil,最后一次测试没有完成,appVersion存储在param中,因为它是nil,你就崩溃了。