iOS学习笔记-134.RunLoop02——Runloop与线程

来源:互联网 发布:android studio 源码 编辑:程序博客网 时间:2024/05/21 22:52

  • RunLoop02Runloop与线程
    • 一通过 CFRunLoopc 的 _CFRunLoopGet0 函数 发现端倪
    • 二Runloop与线程的关系
    • 三代码示例
    • 四运行结果
    • 五结果分析

RunLoop02——Runloop与线程

一、通过 CFRunLoop.c 的 _CFRunLoopGet0 函数 发现端倪

我们首先下载到CFRunloop的源码

https://opensource.apple.com/source/CF/

找到我们 CFRunLoop.c 这个文件,搜索到 _CFRunLoopGet0 函数。

/获得runloop(创建runloop)// should only be called by Foundation// t==0 is a synonym for "main thread" that always worksCF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {    if (pthread_equal(t, kNilPthreadT)) {    t = pthread_main_thread_np();    }    __CFLock(&loopsLock);    if (!__CFRunLoops) {        __CFUnlock(&loopsLock);        // 创建字典    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);        // 创建主线程对应的runloop    CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());        // 使用字典保存主线程-主线程对应的runloop    CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);    if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {        CFRelease(dict);    }    CFRelease(mainLoop);        __CFLock(&loopsLock);    }    // 从字典中获取子线程的runloop    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));    __CFUnlock(&loopsLock);    if (!loop) {        // 如果子线程的runloop不存在,那么就为该线程创建一个对应的runloop    CFRunLoopRef newLoop = __CFRunLoopCreate(t);        __CFLock(&loopsLock);    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));        // 把当前子线程和对应的runloop保存到字典中    if (!loop) {        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);        loop = newLoop;    }        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it        __CFUnlock(&loopsLock);    CFRelease(newLoop);    }    if (pthread_equal(t, pthread_self())) {        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);        }    }    return loop;}

我们可以看到,它会为线程创建一个 runloop 对象,然后存入到 字典中,这样它保持着一一对应的关系。


二、Runloop与线程的关系

1.Runloop和线程的关系:一个Runloop对应着一条唯一的线程。

Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop

问题:如何让子线程不死

回答:给这条子线程开启一个Runloop

2.Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建。

开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用

currentRunLoop 方法来创建,它本身是一个懒加载的

3.Runloop的生命周期:在第一次获取时创建,在线程结束时销毁


三、代码示例

////  ViewController.m//  03_UIView91_NSRunLoop简单运用////  Created by 杞文明 on 17/9/10.//  Copyright © 2017年 杞文明. All rights reserved.//#import "ViewController.h"@interface ViewController ()@end@implementation ViewController-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    //====================Foundation============================    // 1.获取主线程对应的runloop    NSRunLoop * mainRunLoop1 = [NSRunLoop mainRunLoop];    // 2.获取当前线程对应的runloop    NSRunLoop * currentRunLoop1 = [NSRunLoop currentRunLoop];    NSLog(@"%@---------%@",mainRunLoop1,currentRunLoop1);    //====================core foundation============================    // 1.获取主线程对应的runloop    CFRunLoopRef mainRunLoop2 = CFRunLoopGetMain();    // 2.获取当前线程对应的runloop    CFRunLoopRef currentRunLoop2 = CFRunLoopGetCurrent();    NSLog(@"%p---------%p",mainRunLoop2,currentRunLoop2);    //Runloop和线程的关系    //一一对应,主线程的runloop已经创建,但是子线程的需要手动创建    [[[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil] start];}//在runloop中有多个运行模式,但是runloop只能选择一种模式运行//mode里面至少要有一个timer或者是source-(void)run{    NSLog(@"=========run========");    //如何创建子线程对应的runLoop, currentRunLoop懒加载的    //现在还是不行的哦    NSLog(@"%@",[NSRunLoop currentRunLoop]);    NSLog(@"run--%@",[NSThread currentThread]);}@end

四、运行结果

[20640:123485] <CFRunLoop 0x60000016a5c0 [0x103794df0]>......省略了很多输出......---------<CFRunLoop 0x60000016a5c0 [0x103794df0]>......省略了很多输出......[20640:123485] 0x60000016a5c0---------0x60000016a5c0[20640:123682] =========run========[20640:123682] <CFRunLoop 0x60000016b880 [0x103794df0]>{wakeup port = 0x110b, stopped = false, ignoreWakeUps = true, current mode = (none),common modes = <CFBasicHash 0x600000051850 [0x103794df0]>{type = mutable set, count = 1,entries =>    2 : <CFString 0x10376c920 [0x103794df0]>{contents = "kCFRunLoopDefaultMode"}},common mode items = (null),modes = <CFBasicHash 0x600000051220 [0x103794df0]>{type = mutable set, count = 1,entries =>    2 : <CFRunLoopMode 0x600000197830 [0x103794df0]>{name = kCFRunLoopDefaultMode, port set = 0xf07, queue = 0x60000016ba00, source = 0x6000001dfa40 (not fired), timer port = 0x650b,     sources0 = (null),    sources1 = (null),    observers = (null),    timers = (null),    currently 526736125 (7463726825342) / soft deadline in: 1.84467366e+10 sec (@ -1) / hard deadline in: 1.84467366e+10 sec (@ -1)},}}[20640:123682] run--<NSThread: 0x600000269880>{number = 3, name = (null)}

五、结果分析

我们发现 在主线程中 通过 foundation 中

// 1.获取主线程对应的runloopNSRunLoop * mainRunLoop1 = [NSRunLoop mainRunLoop];// 2.获取当前线程对应的runloopNSRunLoop * currentRunLoop1 = [NSRunLoop currentRunLoop];

获取到的对象是同一个。


在主线程中 通过 core foundation 中

// 1.获取主线程对应的runloopCFRunLoopRef mainRunLoop2 = CFRunLoopGetMain();// 2.获取当前线程对应的runloopCFRunLoopRef currentRunLoop2 = CFRunLoopGetCurrent();

获取到的对象是同一个。


core foundation 和 foundation 获取到的对象不是同一个的。这是因为,NSRunLoop 是 对 CFRunLoop 的再次封装.

原创粉丝点击