1. 程式人生 > >PerformSelector 和多執行緒的關係

PerformSelector 和多執行緒的關係

PerformSelector 相關

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

 這三個方法是同步在當前執行緒執行的。會阻塞當前執行緒。可在主執行緒或者子執行緒執行。
比如

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelector:@selector(doSomething:) withObject:@"111"];
    NSLog(@"over");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

列印結果是

doSomething:__111__, currentThread = <NSThread: 0x7fe18c904ac0>{number = 1, name = main}
(2s later...)
doSomething sleep over
over

如果在子執行緒裡做會立即列印 over。子執行緒嘛,當然不會阻塞主執行緒。


PerformSelector:afterDelay 相關

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;

這兩個方法類似,只是第二個方法裡指定了執行緒中 Runloop 的 Modes,這個先不說。
這個方法是非同步的,而且只能在主執行緒中執行。什麼意思呢?

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelector:@selector(doSomething:) withObject:@"ahahaha" afterDelay:0];
    NSLog(@"before sleep");
    sleep(4);
    NSLog(@"after sleep");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
}

列印結果是

before sleep
(4s later...)
after sleep
doSomething:__ahahaha__, currentThread = <NSThread: 0x7fdf73706c70>{number = 1, name = main}

能看出來,這個方法不會阻塞當前執行緒,而是把 Selector 加到主佇列裡,當 delay 之後執行 Selector。如果主執行緒在執行業務,那隻能等到執行完所有業務之後才會去執行 Selector,就算 delay 等於 0。
那 delay 從什麼時候開始計算呢?從 performSelector 的時候。就算這時主執行緒在阻塞也會計算時間,當阻塞結束之後,如果到了 delay 那就執行 Selector,如果沒到就繼續 delay。

PerformSelectorOnMainThread 相關

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// 相關的指定執行緒方法就不提了。一個意思。

這倆方法意思很明確,可以在主或者子執行緒中執行,但 Selector 肯定是在主執行緒中執行。這裡只提一下 waitUntilDone。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self performSelectorOnMainThread:@selector(doSomething:) withObject:@"1111" waitUntilDone:YES];
    NSLog(@"before sleep");
    sleep(2);
    NSLog(@"after sleep");
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

列印結果是

doSomething:__1111__, currentThread = <NSThread: 0x7fc90b5038b0>{number = 1, name = main}
(2s later...)
doSomething sleep over
before sleep
(2s later);
after sleep

很明顯,waitUntilDone == YES 會阻塞當前執行緒,當主執行緒執行完 Selector 之後才會繼續執行當前執行緒。如果是 NO 呢?

before sleep
(2s later...)
after sleep
doSomething:__1111__, currentThread = <NSThread: 0x7fc90b5038b0>{number = 1, name = main}
(2s later);
doSomething sleep over

主執行緒不會阻塞當前執行緒,大家互不干擾。但上述程式碼中的當前執行緒是主執行緒,那麼和 performSelector:afterDelay 類似,主執行緒順序執行完業務之後才會繼續執行 Selector 的業務。如果當前執行緒是子執行緒呢?

- (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_queue_t t1 = dispatch_queue_create("sub queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(t1, ^{
        [self performSelectorOnMainThread:@selector(doSomething:) withObject:@"1111" waitUntilDone:NO];
        NSLog(@"before sleep");
        sleep(2);
        NSLog(@"after sleep");
    });
}

- (void)doSomething:(NSString *)aStr {
    NSLog(@"doSomething:__%@__, currentThread = %@", aStr, [NSThread currentThread]);
    sleep(2);
    NSLog(@"doSomething sleep over");
}

列印結果是

before sleep
doSomething:__1111__, currentThread = <NSThread: 0x7ff7c2603a00>{number = 1, name = main}
(after 2s...)
after sleep
doSomething sleep over

當前執行緒和主執行緒互不干擾,大家是並行的。那如果 waitUntilDone == YES 呢?
當然是等主執行緒執行完之後再接著執行子執行緒裡的業務了。

doSomething:__1111__, currentThread = <NSThread: 0x7fd3a1f03510>{number = 1, name = main}
(2s later...)
doSomething sleep over
before sleep
(2s later...)
after sleep

大致就是這樣。

 


原文連結:https://www.jianshu.com/p/0d16da7ec609