關(guān)于PerformSelector和多線程的知識(shí)點(diǎn)

PerformSelector 相關(guān)

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

這三個(gè)方法是同步在當(dāng)前線程執(zhí)行的。會(huì)阻塞當(dāng)前線程??稍谥骶€程或者子線程執(zhí)行。
比如

- (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");
}

打印結(jié)果是

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

如果在子線程里做會(huì)立即打印 over。子線程嘛,當(dāng)然不會(huì)阻塞主線程。


PerformSelector:afterDelay 相關(guān)

- (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;

這兩個(gè)方法類似,只是第二個(gè)方法里指定了線程中 Runloop 的 Modes,這個(gè)先不說(shuō)。
這個(gè)方法是異步的,而且只能在主線程中執(zhí)行。什么意思呢?

- (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]);
}

打印結(jié)果是

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

能看出來(lái),這個(gè)方法不會(huì)阻塞當(dāng)前線程,而是把 Selector 加到主隊(duì)列里,當(dāng) delay 之后執(zhí)行 Selector。如果主線程在執(zhí)行業(yè)務(wù),那只能等到執(zhí)行完所有業(yè)務(wù)之后才會(huì)去執(zhí)行 Selector,就算 delay 等于 0。
那 delay 從什么時(shí)候開始計(jì)算呢?從 performSelector 的時(shí)候。就算這時(shí)主線程在阻塞也會(huì)計(jì)算時(shí)間,當(dāng)阻塞結(jié)束之后,如果到了 delay 那就執(zhí)行 Selector,如果沒到就繼續(xù) delay。

PerformSelectorOnMainThread 相關(guān)

- (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;
// 相關(guān)的指定線程方法就不提了。一個(gè)意思。

這倆方法意思很明確,可以在主或者子線程中執(zhí)行,但 Selector 肯定是在主線程中執(zhí)行。這里只提一下 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");
}

打印結(jié)果是

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

很明顯,waitUntilDone == YES 會(huì)阻塞當(dāng)前線程,當(dāng)主線程執(zhí)行完 Selector 之后才會(huì)繼續(xù)執(zhí)行當(dāng)前線程。如果是 NO 呢?

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

主線程不會(huì)阻塞當(dāng)前線程,大家互不干擾。但上述代碼中的當(dāng)前線程是主線程,那么和 performSelector:afterDelay 類似,主線程順序執(zhí)行完業(yè)務(wù)之后才會(huì)繼續(xù)執(zhí)行 Selector 的業(yè)務(wù)。如果當(dāng)前線程是子線程呢?

- (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");
}

打印結(jié)果是

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

當(dāng)前線程和主線程互不干擾,大家是并行的。那如果 waitUntilDone == YES 呢?
當(dāng)然是等主線程執(zhí)行完之后再接著執(zhí)行子線程里的業(yè)務(wù)了。

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

大致就是這樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項(xiàng)。當(dāng)然也會(huì)給出幾種多線程的案...
    伯恩的遺產(chǎn)閱讀 275,548評(píng)論 251 2,329
  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項(xiàng)。當(dāng)然也會(huì)給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 684評(píng)論 0 0
  • 一、什么是runloop 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”。它不是線程,但它和線程息息相關(guān)。一般來(lái)講,一個(gè)線程一次...
    WeiHing閱讀 8,300評(píng)論 11 111
  • 燈 火 胡99 2017-04-23 從小至今見過(guò)無(wú)數(shù)的燈火,按發(fā)光體來(lái)分,大致可分為:青油燈,柴火燈,...
    99閱讀 1,025評(píng)論 4 6
  • 艷陽(yáng)下行馬閱讀 121評(píng)論 0 0

友情鏈接更多精彩內(nèi)容