iOS学习笔记-134.RunLoop02——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 works
CF_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.获取主线程对应的runloop
NSRunLoop * mainRunLoop1 = [NSRunLoop mainRunLoop];

// 2.获取当前线程对应的runloop
NSRunLoop * currentRunLoop1 = [NSRunLoop currentRunLoop];

获取到的对象是同一个。


在主线程中 通过 core foundation 中

// 1.获取主线程对应的runloop
CFRunLoopRef mainRunLoop2 = CFRunLoopGetMain();

// 2.获取当前线程对应的runloop
CFRunLoopRef currentRunLoop2 = CFRunLoopGetCurrent();

获取到的对象是同一个。


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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值