05-多线程(4)

0712RunLoop

1、关于Source的说明(02-runloop-source)

05-多线程(4)_第1张图片

source就是事件,处理Source就是处理事件,都是系统来处理的,开发人员用的较少

2、关于Observer的说明(03-runloop03-observer)

05-多线程(4)_第2张图片
- (void)observer
{
    // 创建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
    });

    // 添加观察者:监听RunLoop的状态
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
    // 释放Observer
    CFRelease(observer);
}
/*
    CF的内存管理(Core Foundation)
    1.凡是带有Create、Copy、Retain等字眼的函数,创建出来的对象,都需要在最后做一次release
    * 比如CFRunLoopObserverCreate
    2.release函数:CFRelease(对象);
 */

3、Runloop流程(04-runloop04-整体处理逻辑_)

05-多线程(4)_第3张图片

4、函数调用栈(从下到上执行)

05-多线程(4)_第4张图片

5、Runloop的应用场景

  1. 改变runloop的mode让NSTimer在拖拽表格时也能运行
  2. 让UIImageView在拖拽表格时暂停加载图片,防止卡顿优化用户体验
 - (void)useImageView
{
    // 只在NSDefaultRunLoopMode模式下显示图片
    [self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];
}
  1. 常驻线程

一个线程在执行完它任意一个任务后就会处于消亡状态,接着就会dealloc,消亡状态下即使你强引用他不让他dealloc,该线程也不会再执行任务
Runloop启动之前先要选择Mode,而且要判断这个Mode为不为空,如果为空则一启动就退出,而只要给Mode添加了事件、观察者、定时器三者之一就Mode就不在为空了

  • 第一步:懒加载Runloop[NSRunLoop currentRunLoop]
  • 第二步:给Runloop的一个Mode添加端口(事件)或者定时器(观察者不行),这样可以让Runloop运行一圈后休息不退出保持监听[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]
  • 第三步:让Runloop跑起来[[NSRunLoop currentRunLoop] run]
  • 上述三步完成后该线程执行完当前任务后就可以去执行下一条任务而不被销毁了
  • 还有一种写法如下,但是不推荐
while (1) {
        [[NSRunLoop currentRunLoop] run];
    }
  1. 自动释放池
    手动开启一个子线程的Runloop最好的做法是先用自动释放池包起来,用一个autoreleasepool包起来的作用就是希望它内部的局部变量及时有效的得到释放,比如苹果的main函数里面UIApplicationMain外面就是先用了一个自动释放池包起来的,再比如AFN开启一个常驻子线程时也会这样做

自动释放池创建与销毁的三个时间点
kCFRunLoopEntry; // 创建一个自动释放池
kCFRunLoopBeforeWaiting; // 销毁自动释放池,创建一个新的自动释放池
kCFRunLoopExit; // 销毁自动释放池

 - (void)execute
{
    @autoreleasepool {
        NSLog(@"----------run----%@", [NSThread currentThread]);   
        [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];   
        NSLog(@"---------");
    }
}

6、Runloop面试题

  • 什么是Runloop?
  • 从字面意思看,就是运行循环,或者说跑圈,但并不是说就是不停的跑,没有任务时会休眠,但是开始的时候一个任务都没有的话会一启动就退出
  • 这个循环其实就是do-while循环,不断处理各种任务(Source、Observer、Timer)
  • 一个线程对应一个Runloop,App系统有个保存线程-Runloop键值对的字典。主线程Runloop默认启动,子线程Runloop要先激活(currentRunloop)然后手动启动(Run)
  • Runloop只能选择一个Mode启动,如果当前Mode中没有任何Source、Observer、Timer,那么就会直接退出Runloop
  • 开发中的应用场景?
  • 开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)
    • 在子线程开启一个定时器
    • 在子线程进行长期监控(比如扫描沙盒文件夹改变、Socket内容、语音服务等之类的长时间耗时操作)
  • 可以控制定时器在特定模式下运行
  • 可以让某些事件(行为,任务)在特定模式下执行
  • 可以添加Observer监听Runloop状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)

7、GCD定时器dispatch_source_t timer

  • 与NSTimer和CADisplayLink不同,GCD定时器不在Runloop的Mode里,故不受Mode影响
  • 可以精确到纳秒(1秒=10的9次方纳秒)
  • 这个Timer实际上是一个OC对象,不用dispatch_cancel()
  int count = 0;
  - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 获得队列
//    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 创建一个定时器(dispatch_source_t本质还是个OC对象)
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    // 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
    // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
    // 何时开始执行第一个任务
    // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    dispatch_source_set_timer(self.timer, start, interval, 0);
    
    // 设置回调
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"------------%@", [NSThread currentThread]);
        count++;
//        if (count == 4) {
//            // 取消定时器
//            dispatch_cancel(self.timer);
//            self.timer = nil;
//        }
    });
    // 启动定时器,这个定时器默认是暂停的
    dispatch_resume(self.timer);
}

你可能感兴趣的:(05-多线程(4))