如何在Xcode中按顺序打印文件中所有已执行方法(仅打印一次)?
实现Xcode中按顺序打印已执行方法(仅打印一次)
嘿,我懂你想要的效果——既能拥有系统NSLog自带的时间、进程信息,又能按执行顺序记录每个方法的首次调用,不会重复打印同个方法的日志。下面给你两种实用方案,适配不同的场景:
方案一:全局自动拦截(无需手动修改方法)
这个方案利用Objective-C的**方法交换(Method Swizzling)**特性,自动拦截所有OC方法的调用,记录首次执行的方法,全程无需手动给每个方法加日志代码,非常适合全局调试。
步骤1:创建NSObject分类
新建两个文件:NSObject+MethodLogger.h 和 NSObject+MethodLogger.m
头文件代码:
#import <Foundation/Foundation.h> @interface NSObject (MethodLogger) /// 启用方法日志记录(load方法会自动执行,此方法仅作为显式入口) + (void)enableMethodLogging; @end
实现文件代码:
#import "NSObject+MethodLogger.h" #import <objc/runtime.h> // 存储已打印过的方法签名,避免重复 static NSMutableSet *_loggedMethods; @implementation NSObject (MethodLogger) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _loggedMethods = [NSMutableSet set]; // 交换forwardInvocation:方法,拦截所有方法调用 Method originalMethod = class_getInstanceMethod(self, @selector(forwardInvocation:)); Method swizzledMethod = class_getInstanceMethod(self, @selector(swizzled_forwardInvocation:)); method_exchangeImplementations(originalMethod, swizzledMethod); }); } + (void)enableMethodLogging { // 空方法,仅用于触发load逻辑(实际load会在类加载时自动执行) } - (void)swizzled_forwardInvocation:(NSInvocation *)invocation { SEL methodSelector = invocation.selector; NSString *className = NSStringFromClass([self class]); NSString *methodName = NSStringFromSelector(methodSelector); // 拼接成你想要的格式:-[ClassName methodName:] NSString *fullMethodSignature = [NSString stringWithFormat:@"-%@ %@", className, methodName]; // 检查是否已打印过该方法,仅首次调用时打印 if (![_loggedMethods containsObject:fullMethodSignature]) { [_loggedMethods addObject:fullMethodSignature]; // 直接用NSLog自动生成时间、进程等系统信息 NSLog(@"%@", fullMethodSignature); } // 调用原方法逻辑,不影响原有功能 [self swizzled_forwardInvocation:invocation]; } @end
使用方式
在AppDelegate.m的application:didFinishLaunchingWithOptions:方法里添加一行代码即可启用:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [NSObject enableMethodLogging]; // 其他初始化代码 return YES; }
方案二:手动封装日志宏(仅记录指定方法)
如果你只需要调试特定类的方法,不想全局拦截,那可以封装一个宏,手动添加到需要记录的方法中,同样实现去重和指定格式。
宏定义代码
在你的PCH文件或者公共头文件里添加以下代码:
// 存储已打印方法的集合 static NSMutableSet *_loggedMethods; #define LogUniqueMethod() \ do { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _loggedMethods = [NSMutableSet set]; \ }); \ NSString *className = NSStringFromClass([self class]); \ NSString *methodName = NSStringFromSelector(_cmd); \ NSString *fullMethod = [NSString stringWithFormat:@"-%@ %@", className, methodName]; \ if (![_loggedMethods containsObject:fullMethod]) { \ [_loggedMethods addObject:fullMethod]; \ NSLog(@"%@", fullMethod); \ } \ } while (0)
使用方式
在需要记录的方法里直接调用宏即可:
- (void)viewDidLoad { [super viewDidLoad]; LogUniqueMethod(); // 你的业务代码 } - (void)prepareTableView { LogUniqueMethod(); // 你的业务代码 }
注意事项
- 方案一的风险:Method Swizzling是全局生效的,建议只在Debug模式下启用,避免影响线上代码;同时要注意和其他第三方库的方法交换冲突,尽量在分类的
load方法里用dispatch_once保证只执行一次。 - 日志格式:两种方案都利用系统NSLog自动生成时间、进程ID、线程ID等信息,完全符合你给出的示例格式。
- 去重逻辑:通过
NSMutableSet存储已打印的方法签名,确保每个方法仅在首次执行时被记录。
内容的提问来源于stack exchange,提问作者user9067376
相关产品推荐
相关产品推荐

