assert出问题了?

刚学习Objective-C那会儿,还不太了解这个世界的惯用法,所以有些地方使用了C/C++的方式,虽然后来做过一定的修改, 但是项目中还是遗留了一些无关紧要的C/C++代码。比如对断言的运用。

assert(some != nil); 

问题

使用assert倒是没遇到啥问题,不过有一次在查阅测试同学提交上来的crashlog, 发现竟然崩在了assert调用上。

Thread 0 Crashed:
0   libsystem_kernel.dylib        0x3aaf61fc __pthread_kill + 8
1   libsystem_pthread.dylib       0x3ab5fa2e pthread_kill + 54
2   libsystem_c.dylib             0x3aaa6ff8 abort + 72
3   libsystem_c.dylib             0x3aa86d22 __assert_rtn + 178
4   test                          0x000f8b36 -[AppDelegate application:didFinishLaunchingWithOptions:]
......
15  CoreFoundation                0x300c014a __CFRunLoopRun + 1394
16  CoreFoundation                0x3002ac22 CFRunLoopRunSpecific + 518
17  CoreFoundation                0x3002aa06 CFRunLoopRunInMode + 102
18  UIKit                         0x328d2dd4 -[UIApplication _run] + 756
19  UIKit                         0x328ce044 UIApplicationMain + 1132
20  test                          0x000f8bde main (main.m:16)
21  libdyld.dylib                 0x3aa3fab4 start + 0

还真是稀奇,这到底是怎么回事呢?


缘由

首先,assert不是应该只在NDEBUG没有定义的时候有效么?难道Release默认没有设置这个宏?

通过Xcode日志很容易就发现Release下果然没有设置NDEBUG,验证了前面的假设。

可是为什么Release下默认没有设置这个宏呢?我记得NDEBUG 是语言标准的一部分啊?

查阅文档, 结果如下。

也就是说, NDEBUG确实是语言的标准,但是标准只定义了它是怎么影响assert的, 并没有定义编译器应该在什么情况下定义NDEBUG,所以XcodeRelase模式下没有定义也是合乎标准的。


继续挖掘

问题找到原因了,可是我还是不死心,那如果Xcode是这样对待assert的, 那么自家的NSCAssert呢?

Foundation/NSException.h中,NSCAssert大致是这样的定义的:

#if !defined(NS_BLOCK_ASSERTIONS)
#define NSCAssert(condition, desc, ...) 
    do {               
   __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS 
   if (!(condition)) {     
       [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] 
       file:[NSString stringWithUTF8String:__FILE__] 
           lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; 
   }               
        __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS 
    } while(0)
#else
#define NSCAssert(condition, desc, ...) do {} while (0)
#endif 

assertNDEBUG来控制类似, NSCAssert是由NS_BLOCK_ASSERTIONS控制的。

那么Release下的NSCAssert会不会也会触发程序崩溃呢?

通过查阅XcodeRelease模式下的构建日志,发现答案是不是的。


总结

我只能说Xcode这里做的略不厚道,既然你给自家的NSCAssert定义了开关,那么也应该关照到assert

作为开发人员,我们有两个处理办法。

  • 不用assert, 完全改成NSCAssert(注意不要使用NSAssert,详见这里)。但是要同时注意你使用的第三方代码。
  • 在工程设置Build Settings -> Preprocessor Macros -> Release中添加NDEBUG=1, 如下图。










from:http://imoldman.github.io/blog/2014/04/30/why-assert-enabled-under-release-in-xcode/
原文地址:https://www.cnblogs.com/zsw-1993/p/4879367.html