1. 程式人生 > >多執行緒三: NSThread 面試題

多執行緒三: NSThread 面試題

- (void)viewDidLoad {
   [super viewDidLoad];
   NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
    }];
    [thread start];
    
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}

- (void)test {
    NSLog(@"2");
}

列印結果:
1
然後崩潰
錯誤資訊是:
Terminating app due to uncaught exception ‘NSDestinationInvalidException’, reason: ‘*** -[ViewController performSelector:onThread:withObject:waitUntilDone:modes:]: target thread exited while waiting for the perform’


這是因為

  • test 方法是放在 thread 執行緒中執行的;
  • 當 程式執行到 [thread start] 方法時,initWithBlock 中的 內容已經執行完畢,thread 執行緒就銷燬了。
  • 所以當 執行 test 方法時, 因 thread 執行緒已經被銷燬。自然就崩潰了。

可以新增 runloop 來解決此問題。

    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }];
    [thread start];
    
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];

如果程式碼改成 後 執行 [thread start ] 會發生什麼 ?

- (void)getNSThreadFirst {
    NSLog(@"123");
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
    }];
    
    NSLog(@"456");
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
    
    NSLog(@"789");
    [thread start];
    
    NSLog(@"098");
}

執行結果:
在這裡插入圖片描述

這是因為 相互等待,因為 waitUntilDone = yes 。


把 waitUntilDone 改成 No.

- (void)getNSThreadFirst {
    NSLog(@"123");
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
    }];
    
    NSLog(@"456");
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:NO];
    
    NSLog(@"789");
    [thread start];
    
    NSLog(@"098");
}

執行結果:
在這裡插入圖片描述