刚学习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语言第十一周作业

        这个作业属于哪个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/computer-scienceclass3-2018/ ...

  2. [P5348]密码解锁

    Description 给一个长度为 \(n\) 的数组 \(a[1\dots n]\) ,满足 \(\sum_{m|x}a[x] = \mu(m)\),求 \(a[m]\). \(n\le 10^{ ...

  3. AcWing 875. 快速幂

    题目链接:https://www.acwing.com/problem/content/description/877/ 快速幂模板题,计算ab mod p 的值,a,b,p大概1e9左右,可以快速计 ...

  4. 1、Java语言概述与开发环境——Java特性和技术体系平台

    一.Java语言的主要特性 1.Java语言是易学的: Java语言的语法与C语言和C++语言很接近,使得大多数的程序员很容易学习和使用Java. 2.Java语言是强制面向对象的: Java语言提供 ...

  5. 关系型数据库为什么喜欢使用B+树作为索引结构? (转)

    问题1. 数据库为什么要设计索引? 图书馆存了1000W本图书,要从中找到<架构师之路>,一本本查,要查到什么时候去? 于是,图书管理员设计了一套规则: (1)一楼放历史类,二楼放文学类, ...

  6. Redis---键的过期时间及数据淘汰策略

    5.键的过期时间   Redis可以为每个键设置过期时间,当键过期时,会自动删除该键.   对于散列表这种容器,只能为整个键设置过期时间(整个散列表),而不能为键里面的单个元素设置过期时间. 6.数据 ...

  7. django后台返回html字段会产生XSS防护的解决方式

    1.在前端模块里面写 {{  page_str|safe }} 2.在后端 from django.utils.safestring import mark_safe pake_str = mark_ ...

  8. Animator通过按键切换动画不及时,动画延时切换问题

    再unity3D版本为Unity 5.2.1f1 (64-bit),再设置动画切换时有一个Has Exit Time属性,由于勾上了这个的原因

  9. thinkphp5发送邮件(实例代码 非常适合新手)

    第一步:在(https://pan.baidu.com/s/1Fq6lONHlft5D6jvOnNwtoA)下载 phpmailer.rar 解压 然后把文件放入 vendor目录下 第二步:在 ap ...

  10. Mysql逻辑架构介绍

    总体概览: 和其它数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用.主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离 ...