如何自定义包含类、行号及格式化的NSAssert宏?
自定义带类信息和行号的NSAssert宏方案
我完全懂你的需求——既然已经把NSLog改造成了带类名的样式,肯定也想让NSAssert跟上这个节奏,而且不想手动拆分参数,要像用原生NSAssert一样顺手对吧?其实我们可以借助Objective-C宏的可变参数特性,结合预定义的编译宏来实现,下面给你几个实用的方案:
基础版:直接扩展NSAssert格式
这个方案最贴近你的自定义NSLog逻辑,直接把类名、行号拼到断言消息的前面,用法和原生NSAssert完全一致:
#define DebugAssert(condition, format, ...) \ NSAssert(condition, @"[%@:%d] " format, NSStringFromClass([self class]), __LINE__, ##__VA_ARGS__)
用法示例:
DebugAssert(self.dataArray.count > 0, @"数据数组不能为空"); // 断言失败时会输出:[YourClassName:42] 数据数组不能为空
这里的##__VA_ARGS__是用来处理没有可变参数的情况(比如只传condition和一个简单字符串),避免出现编译警告。而且因为用了[self class],这个宏在实例方法和类方法里都能正常工作——类方法里的self本身就是类对象,NSStringFromClass([self class])依然能正确输出类名。
进阶版:支持无自定义消息的场景
如果有时候你不想写自定义消息,只想让断言失败时默认显示类和行号,可以优化一下宏,让它支持空消息的情况:
#define DebugAssert(condition, ...) \ do { \ NSString *assertMessage = (sizeof(#__VA_ARGS__) == 1) ? @"断言失败" : [NSString stringWithFormat:__VA_ARGS__]; \ NSAssert(condition, @"[%@:%d] %@", NSStringFromClass([self class]), __LINE__, assertMessage); \ } while(0)
用法示例:
// 不带自定义消息 DebugAssert(self.dataArray.count > 0); // 断言失败输出:[YourClassName:42] 断言失败 // 带自定义消息 DebugAssert(self.dataArray.count > 0, @"数据数组长度必须大于0,当前长度:%lu", (unsigned long)self.dataArray.count); // 断言失败输出:[YourClassName:42] 数据数组长度必须大于0,当前长度:0
这里用do-while(0)包裹是为了避免宏在复杂语句(比如if分支)里出现语法错误,这是自定义宏的常见技巧。
注意事项
- 这个宏依赖
self,所以只能在类的方法内部使用,如果要在全局函数里用,需要把类名参数改成手动传入的形式。 - 如果你的项目开启了
NS_BLOCK_ASSERTIONS(比如Release模式),这些自定义断言会和原生NSAssert一起被自动禁用,不用担心发布版本里的性能问题。
内容的提问来源于stack exchange,提问作者COOKIES
相关产品推荐
相关产品推荐

