刚学习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. 11g Oracle Rac安装(基于linux6)

    安装 Oracle 11gR2 RAC on Linux 6 本文介绍如何在Oracle Linux 6上安装2节点Oracle 11gR2 Real Application Cluster(RAC) ...

  2. P5020货币系统

    这个题是2018提高组真题,是一道看不出是背包的背包题. 题干特别长,甚至有些没看懂.题意为给出一组货币面值,然后从这里面用最少的面值数量取代原先的面值.比如3,6直接用3表示.一开始想到了小凯的疑惑 ...

  3. P1190排队接水

    这是2010年普及组第二题(话说我怎么只做普及组的题?因为太蒻). 这道题可以用搜索或者模拟来做,果断编了几组例子去分析来模拟,利用了贪心的思想得出:每次比较每个水龙头的空闲时间点,谁早就放到谁那里, ...

  4. 题解 AT1357 【n^p mod m】

    此题就是快速幂取模 先简单讲一讲快速幂 首先,快速幂的目的就是做到快速求幂,假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,快速幂能做到O(logn) ...

  5. 剑指offer-树的子结构-python

    题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构)     思路 空树不是任意一个树的子结构,如果 root1 与root2 中有一个为空树的话,返回 ...

  6. install python+twisted+mysqldb+django on mac

    一. install python 1) check install or not 在mac终端输入命令:which python 即可查看python的路径 2)未安装时,手动下载安装包 地址:ht ...

  7. spring服务器接收参数格式

    注:@RequestParam 或@RequestBody等注解是否添加有什么区别 不加:参数可有可无,无参数时为null,但当参数类型是 数字基本类型(int.double)时会报错: 加上@Req ...

  8. gradle上sourceSets配置&同名文件合并问题

    gradle的sourceSets可以对不同的buildType, productFlavor,buildVariant设置不同的文件路径,进行多样化处理. sourceSets{ main{ man ...

  9. Django之modles 多对多创建第三张表

    一.第一种:纯自动创建第三张表 纯自动 class Book(models.Model): title = models.CharField(max_length=32) price = models ...

  10. python基础操作---string

    #coding:utf-8 var1 = 'Hello World!' print var1[::] print len(var1) print var1[0:len(var1)] print var ...