3

我在 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

然后崩溃('对象不能为零(键:appversion)')。

调试构建返回:

a
b
c
d
e
g
h

什么是零,但不是零?

4

3 回答 3

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__与每个参数相关联,而不仅仅是它旁边的参数(无论如何都是为了优化目的)。

于 2015-04-18T19:34:48.883 回答
0

结果看起来很奇怪。有一篇不错的文章;谷歌搜索 Chris Lattner(Swift 的首席开发人员,所以他应该知道他在说什么)的“每个程序员应该知道的关于未定义行为的知识”。

看起来,在第一个 NSLog 语句之后,优化编译器决定 appVersion 不可能为 nil,因为将 nil 传递给 NSLog 将是未定义的行为。这就解释了为什么不打印 a 到 e。

打印“h”,因为 appVersion 是一个 64 位指针,int 只有 32 位,所以将非 nil appVersion 转换为 int的结果可能为零。即使确定 appVersion 不为零,优化器也无法删除该检查。

而且因为编译器确定 appVersion 不是 nil,所以最后一个测试没有完成,appVersion 被存储到 param 中,因为它是 nil,所以你崩溃了。

于 2015-04-18T19:16:52.333 回答
0

检查 [NSNull null]

NSNull 类定义了一个单例对象,用于在禁止将 nil 作为值的情况下(通常在数组或字典等集合对象中)表示空值。

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/NumbersandValues/Articles/Null.html

于 2015-04-18T18:10:18.563 回答