開發階段大量使用 NSLog 除錯是常態,但發布版本保留這些日誌會洩露敏感資訊、影響效能、佔用儲存空間。本文介紹透過**巨集定義**與 **Xcode Build Configuration** 實現:Debug 模式完整輸出、Release 模式自動禁用/重導向,且不修改業務代碼。
利用 Xcode 預設的 DEBUG=1 (Debug 配置) 與 DEBUG=0 (Release 配置) 差異,定義條件編譯巨集:
// PrefixHeader.pch 或專用 DebugLog.h
#ifdef DEBUG
#define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define DLog(...) do {} while (0)
#endif
// 保留錯誤日誌永遠輸出
#define ELog(fmt, ...) NSLog((@"[ERROR] %s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
// DDLog.h - 參考 CocoaLumberjack 設計模式
typedef NS_ENUM(NSUInteger, DDLogLevel) {
DDLogLevelOff = 0,
DDLogLevelError = 1,
DDLogLevelWarning = 2,
DDLogLevelInfo = 3,
DDLogLevelDebug = 4,
DDLogLevelVerbose = 5
};
#ifndef DDLogLevel
#ifdef DEBUG
#define DDLogLevel DDLogLevelVerbose
#else
#define DDLogLevel DDLogLevelWarning
#endif
#endif
#define DDLog(level, fmt, ...) \
do { \
if (level <= DDLogLevel) { \
NSLog((@"<%@> %s [Line %d] " fmt), @#level, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
// 使用範例
DDLog(DDLogLevelDebug, @"使用者登入: %@", username);
DDLog(DDLogLevelError, @"網路請求失敗: %@", error);
Preprocessor Macros (或 GCC_PREPROCESSOR_DEFINITIONS)DEBUG=1 (Xcode 預設已有)DEBUG 或設為 DEBUG=0-D DEBUG (Debug) / 留空 (Release)生產環境仍需關鍵錯誤追蹤,建議整合成熟日誌框架:
// CocoaLumberjack 快速整合 (Podfile)
pod 'CocoaLumberjack/Swift'
// AppDelegate.swift
import CocoaLumberjack
DDLog.add(DDOSLogger.sharedInstance) // Xcode Console
let fileLogger = DDFileLogger()
fileLogger.rollingFrequency = 86400 // 24 小時輪轉
fileLogger.logFileManager.maximumNumberOfLogFiles = 7
DDLog.add(fileLogger)
// 使用
DDLogDebug("除錯資訊")
DDLogError("嚴重錯誤: \(error)")
| 場景 | 建議方案 |
|---|---|
| 純 Objective-C 專案 | PrefixHeader.pch 定義 DLog/ELog 巨集 |
| Swift/OC 混編專案 | 共用 .h 檔 + Bridging-Header 引入 |
| 需求日誌分級、持久化、上傳 | 整合 CocoaLumberjack / SwiftyBeaver |
| CI/CD 自動化打包 | 確認 Release 配置無 DEBUG 巨集、Strip 符號表 |
| 隱私合規 (GDPR/個資法) | Release 版嚴禁輸出用戶 ID、Token、位置等敏感欄位 |
#ifdef DEBUG 包裹每行 NSLog → 維護困難、程式碼雜亂#define NSLog(...) 覆蓋系統函數 → 影響第三方庫、行為不可預期