Objective-C 開發中,善用編譯器內建宏與 _cmd 隱式參數,能在日誌中自動輸出方法名、行號、文件、類名、調用棧,極大提升調試效率。本文匯總常用宏、表達式與實戰範例。
| 宏 | 格式 | 說明 |
|---|---|---|
__func__ | %s | 當前函數名(C99) |
__LINE__ | %d | 源碼行號 |
__FILE__ | %s | 文件完整路徑 |
__PRETTY_FUNCTION__ | %s | 含簽名的函數名(C++/ObjC 更豐富) |
| 表達式 | 格式 | 說明 |
|---|---|---|
NSStringFromSelector(_cmd) | %@ | 當前選擇器名(方法名) |
NSStringFromClass([self class]) | %@ | 當前對象類名 |
[[NSString stringWithUTF8String:__FILE__] lastPathComponent] | %@ | 文件名(不含路徑) |
[NSThread callStackSymbols] | %@ | 調用棧符號陣列(僅調試用) |
NSMutableArray *someObject = [NSMutableArray array];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);
[someObject addObject:@"foo"];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);
輸出:
-[ViewController viewDidLoad]:12 someObject=() -[ViewController viewDidLoad]:14 someObject=(foo)
#define DLog(fmt, ...) NSLog((@"%s:%d " fmt), __func__, __LINE__, ##__VA_ARGS__)
#define DLogObj(obj) NSLog(@"%s:%d %@=%@", __func__, __LINE__, #obj, obj)
// 使用
DLog(@"userId=%d", userId);
DLogObj(someArray);
#ifdef DEBUG
#define DLog(fmt, ...) NSLog((@"%s:%d " fmt), __func__, __LINE__, ##__VA_ARGS__)
#else
#define DLog(...)
#endif
// 1. 斷點條件配合
// 2. 監控變量變化
// 3. 記憶體地址追蹤
NSLog(@"obj=%p, retainCount=%lu", obj, (unsigned long)[obj retainCount]);
// 4. 方法調用鏈
NSLog(@"Stack:\n%@", [NSThread callStackSymbols]);
__func__ 在 ObjC 方法中返回 -[Class method] 格式_cmd 是隱式參數,無需聲明直接用callStackSymbols 性能較差,**僅調試使用,勿上線**將 __func__、__LINE__、_cmd、self.class 組合進日誌巨集,實現「零成本」上下文感知日誌,是專業 iOS/macOS 開發者必備技能。