刚学习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/

assert出问题了?的更多相关文章

  1. error BK1506 : cannot open file '.\Debug\????????.sbr': No such file or dire

    http://blog.csdn.net/shuilan0066/article/details/8738035 分类:            调试错误信息2013-03-29 19:08492人阅读 ...

  2. KillTimer不能放在析构函数,可以放在DestroyWindow函数里

    转自 https://www.cnblogs.com/huking/archive/2009/11/27/1612201.html KillTimer&析构函数 析构函数中不能用KillTim ...

  3. 写出将字符串中的数字转换为整型的方法,如:“as31d2v”->312,并写出相应的单元测试,正则去掉非数值、小数点及正负号外的字符串

    写出将字符串中的数字转换为整型的方法,如:"as31d2v"->312,并写出相应的单元测试,输入超过int范围时提示不合法输入. public struct Convert ...

  4. C 标准库系列之assert.h

    先简单介绍一下<assert.h>头文件,该头文件的目的便是提供一个宏assert的定义,即可以在程序必要的地方使用其进行断言处理:断言在程序中的作用是当在调试模式下时,若程序给出的前提条 ...

  5. 剑指Offer面试题:20.栈的压入、弹出序列

    一.题目:栈的压入.弹出序列 题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1.2.3.4.5是某栈的压栈序列,序列4 ...

  6. 窥探Swift编程之错误处理与异常抛出

    在Swift 2.0版本中,Swift语言对其错误处理进行了新的设计,当然了,重新设计后的结果使得该错误处理系统用起来更爽.今天博客的主题就是系统的搞一下Swift中的错误处理,以及看一下Swift中 ...

  7. 断言(Assert)与异常(Exception)

    断言是被用来检查非法情况而不是错误情况,即在该程序正常工作时绝不应该发生的非法情况,用来帮助开发人员对问题的快速定位.异常处理用于对程序发生异常情况的处理,增强程序的健壮性.容错性,减少程序使用中对用 ...

  8. java 关键字 assert的学习

    之前在学习java源码时,发现了assert这个不常用的关键字.下面直接来介绍下这个关键字的使用. assert是什么? 它是jdk1.4之后新增加的关键字,没了. assert的作用是什么? ass ...

  9. (转)assert 断言式编程

    编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设,可以将断言看作是异常处理的一种高级形式.断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真.可以在任何时候启用 ...

随机推荐

  1. Java中HashMap扩容机制思考

    1. HashMap在什么条件下扩容 判断HashMap的数组Size大小如果超过loadFactor*capacity,就要扩容. 相关的类属性: capacity:当前数组容量,始终保持 2^n, ...

  2. C++中的赋值操作符重载和拷贝构造函数

    1,关于赋值的疑问: 1,什么时候需要重载赋值操作符? 2,编译器是否提供默认的赋值操作符? 2,关于赋值的疑问: 1,编译器为每个类默认重载了赋值操作符: 1,意味着同类型的类对象可以相互赋值: 2 ...

  3. [Codeforces 1246B] Power Products (STL+分解质因数)

    [Codeforces 1246B] Power Products (STL+分解质因数) 题面 给出一个长度为\(n\)的序列\(a_i\)和常数k,求有多少个数对\((i,j)\)满足\(a_i ...

  4. [BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)

    [BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆) 题面 有一个装球机器,构造可以看作是一棵树.有下面两种操作: 从根放入一个球,只要下方有空位,球会沿着树滚下.如果 ...

  5. Linux下libaio的一个简单例子

    转载:http://www.cnblogs.com/aLittleBitCool/archive/2011/10/18/2216646.html 异步io,很好玩的一个东西,从接口来看,封装的比较厉害 ...

  6. Python 入门之Python基础数据类型及其方法

    Python 入门之Python基础数据类型 1. 整型:int 用于计算,用于比较 (在赋值的时候先执行等号右边的内容) 1.1 整数的加 a = 10 b = 20 print(a + b) 结果 ...

  7. 工作日记之查看Linux系统里面的启动频率2017_02_07

    链接:http://www.jb51.net/LINUXjishu/19905.html 查看Linux里面的batch: cat /etc/crontab (1)0 19 * * 6 root /d ...

  8. css重置的各种版本总结

    个人手机端常用到的: @charset "utf-8"; body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ...

  9. 关于代码手写UI,xib和StoryBoard

    代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用.Geek们喜欢用代码构建UI,是因为代码是键盘敲出来的,这样可以做到不开IB,手不离开键盘就完成工作,可以专注于编码环境, ...

  10. Hibernate:基于HQL实现数据查询

    HQL:  hibernate query language(hibernate特有的查询语言) hql是基于对象的查询语言,其语法与sql类似,但是他和sql的区别在于sql是面向表和字段的查询,而 ...