刚学习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. C++ vector、list和deque的区别 (整理)

    1.vector数据结构 vector和数组类似,拥有一段连续的内存空间,并且起始地址不变.因此能高效的进行随机存取,时间复杂度为o(1);但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内 ...

  2. 安装OpenStack计算服务(nova)

    1. 配置数据库 数据库安装在控制节(controller)点上 $ mysql -u root -p 2.创建 glance 数据库 CREATE DATABASE nova; GRANT ALL ...

  3. 04: DjangoRestFramework使用

    Django其他篇 目录: 1.1 DjangoRestFramework基本使用 1.2 drf认证&权限 模块 1.3 djangorestframework 序列化 1.4 django ...

  4. Redis持久化存储与主从复制

    4. redis持久化 Redis是一种内存型数据库,一旦服务器进程退出,数据库的数据就会丢失,为了解决这个问题,Redis提供了两种持久化的方案,将内存中的数据保存到磁盘中,避免数据的丢失. 4.1 ...

  5. 3-6如何在一个for语句中迭代多个可迭代对象

    1.并行迭代 迭代元组可以进行拆包迭代. >>> zip([1,2,3,4],('a','b','c','d')) [(1, 'a'), (2, 'b'), (3, 'c'), (4 ...

  6. vuex介绍和vuex数据传输流程

    1.什么是vuex? 公共状态管理:解决多个非父子组件传值麻烦的问题:简单说就是多个页面都能用Vuex中store公共的数据 a.并不是所有的数据都要放在Vuex中,只有各个组件公用的一些数据会放在V ...

  7. oracle数据库ID自增长--序列

    什么是序列?在mysql中有一个主键自动增长的id,例如:uid number primary key auto_increment;在oracle中序列就是类似于主键自动增长,两者功能是一样的,只是 ...

  8. [七月挑选]IntelliJ IDEA常用设置

    title: IntelliJ IDEA常用设置 设置idea的类注释快捷键 File -> Settings -> Live Templates 1.右边的 + -> Templa ...

  9. 34. Find First and Last Position of Element in Sorted Array (JAVA)

    Given an array of integers nums sorted in ascending order, find the starting and ending position of ...

  10. linux 启动和关闭 MySQL

    建议使用 mysqld_safe 命令启动,因为该命令添加了安全特性,当服务器发生错误时自动重启并且 把运行信息记录错误发送到日志文件!命令格式如下: mysqld_safe options 命令的常 ...