Objective-C中NSThread调用触发NSInvalidArgumentException问题排查
问题分析与解决方案
首先咱们来拆解你遇到的NSInvalidArgumentException错误——这个报错的核心原因有两个,咱们一个个说:
1. NSThread初始化的参数完全用错了
你在callInBackground:selector:方法里写了这段代码:
NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(selector) object:nil];
这里犯了两个致命错误:
- 线程的
target你传成了self(也就是QAFeatTestCaseBase的实例),但实际上要执行的Bug8772方法是在子类Bug8772里定义的,所以应该用传入的target参数; @selector(selector)是硬编码的错误写法——你需要用方法参数里的selector,而不是把selector当成方法名,这就是错误提示里说“target does not implement selector”的直接原因,因为QAFeatTestCaseBase根本没有叫selector的方法。
2. 方法命名不符合Objective-C规范(非报错原因,但建议修正)
你的业务方法Bug8772应该遵循Objective-C的命名惯例,用小写字母开头,比如改成bug8772,这样代码可读性更高,也符合行业习惯。
修正后的callInBackground:selector:方法
- (void)callInBackground:(id)target selector:(SEL)selector { // 这里改用传入的target和selector参数,而不是self和硬编码的@selector(selector) NSThread* thread = [[NSThread alloc] initWithTarget:target selector:selector object:nil]; [thread setStackSize: 2*1024*1024]; [thread start]; while([thread isFinished] == NO) { usleep(1000); } [thread release]; }
测试类的调用部分如果改了方法名,记得同步更新selector:
@interface Bug8772 : QAFeatTestCaseBase @end @implementation Bug8772 - (void) testBug8772 { [self callInBackground:self selector:@selector(bug8772)]; } - (void)bug8772 { // do stuff.. } @end
更优的实现方式(避免低效的忙等)
你现在用while循环+usleep的方式等待线程完成,属于忙等,会白白浪费CPU资源。在Objective-C里有更优雅的替代方案:
方式1:用GCD(苹果推荐的并发方式)
GCD会自动管理线程池,代码简洁且高效,还不用手动处理线程生命周期:
- (void)callInBackground:(id)target selector:(SEL)selector { // dispatch_sync会自动等待后台任务执行完成 dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [target performSelector:selector]; }); }
方式2:用NSThread的原生等待方法
如果你坚持要用NSThread,可以用waitUntilDone:替代手动循环,它会让当前线程休眠直到目标线程完成,比忙等高效得多:
- (void)callInBackground:(id)target selector:(SEL)selector { NSThread* thread = [[NSThread alloc] initWithTarget:target selector:selector object:nil]; [thread setStackSize: 2*1024*1024]; [thread start]; // 直接等待线程完成,无需手动循环 [thread waitUntilDone:YES]; [thread release]; }
内容的提问来源于stack exchange,提问作者Gerald
相关产品推荐
相关产品推荐

