解決performSelector afterDelay在子線程不調(diào)用問(wèn)題

有時(shí)候你會(huì)發(fā)現(xiàn)performSelector延時(shí)不起作用,啥原因呢
先看下面的例子

- (void)viewDidLoad {
    [super viewDidLoad];
    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
    [thread setName:@"com.will.thread"];
    [thread start];
}

- (void)threadRun{
    [self performSelector:@selector(runTime1) withObject:nil];
    [self performSelector:@selector(runTime2) withObject:nil afterDelay:1];
    [self performSelector:@selector(runTime2) withObject:nil afterDelay:1 inModes:@[NSDefaultRunLoopMode]];
}

- (void)runTime1{
    NSLog(@"xxoo1");
}

- (void)runTime2{
    NSLog(@"xxoo2");
}
image.png

為什么延時(shí)函數(shù)沒(méi)有調(diào)用,因?yàn)槟阍谧泳€程里調(diào)用延時(shí)函數(shù),需要定時(shí)器,而子線程不同于主線程不會(huì)自動(dòng)創(chuàng)建runloop,導(dǎo)致定時(shí)器沒(méi)有工作,
解決方法有四種:

  • 在子線程里啟動(dòng)runloop
- (void)threadRun{    
    [self performSelector:@selector(runTime2) withObject:nil afterDelay:1];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    [runLoop run];
}
  • performSelector設(shè)定主線程,不過(guò)沒(méi)法設(shè)置延時(shí)函數(shù)
- (void)threadRun{
    [self performSelector:@selector(runTime2) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO];
    //或者:
    [self performSelectorOnMainThread:@selector(runTime2) withObject:nil waitUntilDone:NO];
}
  • 專門設(shè)定在已經(jīng)開(kāi)啟了runloop的線程
- (void)threadRun{
    [self performSelector:@selector(runTime2) onThread:[[self class] _networkThread] withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];
}

+ (void)_addRunLoop:(NSThread *)thread{
    @autoreleasepool {
        [[NSThread currentThread] setName:@"com.will.webimage.request"];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)_networkThread{
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(_addRunLoop:) object:nil];
    [NSThread sleepForTimeInterval:1];
    [thread start];
    return thread;
}
  • 直接用GCD的延時(shí)方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self runTime2];
});

注意:

  • performSelector若不指定mode([self performSelector:@selector(method) withObject:nil];),默認(rèn)自動(dòng)創(chuàng)建mode為NSDefaultRunLoopMode

  • performSelector:onThread:withObject:waitUntilDone里waitUntilDone為NO,則會(huì)等待當(dāng)前線程執(zhí)行完,再執(zhí)行selector里的方法

- (void)threadRun{    
    [self performSelector:@selector(runTime2) onThread:[NSThread currentThread] withObject:nil waitUntilDone:NO];
    
    NSLog(@"com.will.thread執(zhí)行完畢");
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    [runLoop run];
}

打印如下


image.png
最后編輯于
?著作權(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)容

  • 一、什么是runloop 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”。它不是線程,但它和線程息息相關(guān)。一般來(lái)講,一個(gè)線程一次...
    WeiHing閱讀 8,329評(píng)論 11 111
  • ======================= 前言 RunLoop 是 iOS 和 OSX 開(kāi)發(fā)中非?;A(chǔ)的一個(gè)...
    i憬銘閱讀 1,000評(píng)論 0 4
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的,也是非常重要的, 在面試過(guò)程中是經(jīng)常會(huì)被問(wèn)到的, ...
    made_China閱讀 1,278評(píng)論 0 7
  • 一、RunLoop 的概念 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”,RunLoop 實(shí)際上就是一個(gè)事件循環(huán)對(duì)象,這個(gè)對(duì)象...
    風(fēng)輕魚蛋閱讀 581評(píng)論 0 1
  • 風(fēng)說(shuō), 你傷透了我的心, 我溫柔的撩起你額頭的發(fā), 為你吹落一地桃花。 你在陽(yáng)光下開(kāi)心的笑, 那是我見(jiàn)過(guò)的最純真的...
    麥草店主閱讀 150評(píng)論 0 0

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