Runloop

RunLoop詳解

runloop的本質(zhì)是一個(gè)對(duì)象,這個(gè)對(duì)象有一個(gè)入口函數(shù),執(zhí)行入口函數(shù)之后就會(huì)進(jìn)入一個(gè)do while循環(huán),循環(huán)的處理一些事情。

沒(méi)有runloop的情況下,程序運(yùn)行完成就會(huì)退出。
有runloop的時(shí)候程序運(yùn)行完成的時(shí)候不會(huì)退出

runloop的作用

  1. 保持程序持續(xù)運(yùn)行
  2. 處理app中的各種事件(觸摸、定時(shí)器、performselector等)
  3. 節(jié)省cpu資源,提高程序性能(有事件的餓時(shí)候處理事件,沒(méi)事件的時(shí)候休息,可以在main函數(shù)中直接返回1進(jìn)行測(cè)試)

線程和runloop

  1. 線程和runloop是一一對(duì)應(yīng)的關(guān)系(內(nèi)部是一個(gè)字典,key為線程,value為runloop)
  2. 線程創(chuàng)建的時(shí)候,并沒(méi)有創(chuàng)建runloop對(duì)象,runloop會(huì)在第一次獲取的時(shí)候自動(dòng)創(chuàng)建
  3. 主線程默認(rèn)開(kāi)啟了runloop,子線程默認(rèn)沒(méi)有開(kāi)啟runloop

runloop的mode

  1. 一個(gè)runloop對(duì)應(yīng)一個(gè)線程
  2. 一個(gè)runloop包含多個(gè)mode,每個(gè)mode包含若干個(gè)source、timer、observer
  3. source、timer、observer又叫modeitem,不同的mode下mode item 互不影響
  4. runloop運(yùn)行過(guò)程中,只會(huì)選擇一種模式運(yùn)行
  5. 切換mode,程序退出當(dāng)前mode,再重新制定mode執(zhí)行

ModeItem

source0事件
  1. 觸摸事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"testRunloop"); //打斷點(diǎn)可以看到堆棧信息中 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
}
  1. 自定義輸入園source0
- (void)testAction:(UIButton *)sender
{
    NSThread *subThread = [[NSThread alloc]initWithBlock:^{
        CFRunLoopSourceContext context = {
            0,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            schedule,
            cancel,
            perform
        };
        CFRunLoopSourceRef source0 = CFRunLoopSourceCreate(CFAllocatorGetDefault(), 0, &context);
        //有下面一行才能觸發(fā)schedule回調(diào)
        CFRunLoopAddSource(CFRunLoopGetCurrent(), source0, kCFRunLoopDefaultMode);
        
        //有以下代碼才能觸發(fā)perform回調(diào)
        CFRunLoopSourceSignal(source0);
        CFRunLoopWakeUp(CFRunLoopGetCurrent());
        //觸發(fā)cancel回調(diào)
        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source0, kCFRunLoopDefaultMode);
        CFRelease(source0); //釋放
    }];
    [subThread start];
}
void schedule(void *info, CFRunLoopRef rl, CFRunLoopMode mode)
{
    NSLog(@"currentThreed ===%s",__func__);
}

void cancel(void *info, CFRunLoopRef rl, CFRunLoopMode mode)
{
    NSLog(@"currentThreedMode ===%s",__func__);
}

void perform(void *info)
{
  NSLog(@"currentThreedInfo ===%s",__func__);
}
  1. performSelector:onThread:方法調(diào)用
[self performSelectorOnMainThread:@selector(animation:) withObject:nil waitUntilDone:NO];
- (void)animation:(id)sender
{
    NSLog(@"哈哈"); //此處打斷點(diǎn)可以在堆棧中看到 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
}
source1
  1. 端口(NSPort)----

注意測(cè)試代碼在模擬器上控制臺(tái)能打印出來(lái)在手機(jī)上不行,原因是通過(guò)NSPort的port類(lèi)方法創(chuàng)建出來(lái)的是它的子類(lèi)對(duì)象NSMachPort,而Foundation框架給我們提供的NSPort的三個(gè)子類(lèi)中NSMachPort和NSMessagePort只能用于同一臺(tái)機(jī)器上的通信,NSSocketPort可以用于本地和遠(yuǎn)程通信。

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.mainPort = [NSPort port];
    self.mainPort.delegate = self;
    [[NSRunLoop currentRunLoop] addPort:self.mainPort forMode:NSDefaultRunLoopMode];

    NSThread *testThread = [[NSThread alloc]initWithBlock:^{
        self.subPort = [NSPort port];
        self.subPort.delegate = self;
        [[NSRunLoop currentRunLoop] addPort:self.subPort forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    }];
    [testThread setName:@"subThread"];
    [testThread start];
}

- (IBAction)testAction:(UIButton *)sender
{
    NSMutableArray *conmponents = [NSMutableArray array];
    [conmponents addObject:[@"fromMainThread" dataUsingEncoding:NSUTF8StringEncoding]];
    [self.subPort sendBeforeDate:[NSDate date] components:conmponents from:self.mainPort reserved:0];
}

- (void)handlePortMessage:(id)message
{
    NSMutableArray *array = [message valueForKey:@"components"]; //此處打斷點(diǎn)可以在堆棧中看到__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__說(shuō)明這是一個(gè)source1源
    NSString *password = [[NSString alloc]initWithData:[array  firstObject] encoding:NSUTF8StringEncoding];
    NSLog(@"thread ===%@\tpassword===%@", [NSThread currentThread], password);
    if (![[NSThread currentThread] isMainThread]) {
        NSMutableArray *conmponents = [NSMutableArray array];
        [conmponents addObject:[@"fromSubthread" dataUsingEncoding:NSUTF8StringEncoding]];
        [self.mainPort sendBeforeDate:[NSDate date] components:conmponents from:self.subPort reserved:0];
    }
}
計(jì)時(shí)源
  1. NStimer
  2. performSelector:withObject:afterDelay
[self performSelector:@selector(animation:) withObject:nil afterDelay:3];
- (void)animation:(id)sender
{
    NSLog(@"哈哈"); //此處打斷點(diǎn)可以在堆棧中看到 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
}
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • ======================= 前言 RunLoop 是 iOS 和 OSX 開(kāi)發(fā)中非常基礎(chǔ)的一個(gè)...
    i憬銘閱讀 989評(píng)論 0 4
  • RunLoop 的概念 一般來(lái)講,一個(gè)線程一次只能執(zhí)行一個(gè)任務(wù),執(zhí)行完成后線程就會(huì)退出。如果我們需要一個(gè)機(jī)制,讓線...
    Mirsiter_魏閱讀 677評(píng)論 0 2
  • 前言 RunLoop是iOS和OSX開(kāi)發(fā)中非常基礎(chǔ)的一個(gè)概念,這篇文章將從CFRunLoop的源碼入手,介紹Run...
    暮年古稀ZC閱讀 2,411評(píng)論 1 19
  • 轉(zhuǎn)自http://blog.ibireme.com/2015/05/18/runloop 深入理解RunLoop ...
    飄金閱讀 1,087評(píng)論 0 4
  • 摸金派:弟子名稱“摸金校尉",掌門(mén)祖師——曹操。摸金派的來(lái)頭可不小,據(jù)說(shuō)當(dāng)年曹操為了籌集軍費(fèi),專(zhuān)門(mén)組建了一支盜墓軍...
    尋夢(mèng)er閱讀 2,254評(píng)論 1 12

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