RunLoop浅析

2018-03-30  本文已影响22人  woniu

一、什么是RunLoop

a、RunLoop实质上是一个死循环,保证程序持续运行,只有程序退出的时候才会结束。如下,在main.m文件中:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
//开启主线程,同时默认开启主线程的RunLoop。
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

二、RunLoop使用原理和注意点

a、一个RunLoop包含若干个Mode,每个Mode又包含若干个Source、Observer、Timer
b、每次RunLoop启动,只能指定一个Mode,这个Mode被称为CurrentMode
c、如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入, 以使不同组之间的Source、Observer、Timer互不受影响

三、RunLoop和线程的关系

a、RunLoop与线程一一对应,且是管理线程的。
b、RunLoop在主线程默认开启,在子线程中是懒加载。线程执行完毕之后进入休眠状态,有任务就会被唤醒。
c、RunLoop在第一次获取时被创建,在线程结束时被销毁。
d、对于子线程中的定时器,由于RunLoop是懒加载,只有我们使用的时候才会创建,所以要确保子线程的RunLoop被创建,不然定时器不会回调。

NSRunLoop *loop = [NSRunLoop currentRunLoop];
[loop run];

NSTimer和RunLoop的关系:
a、在子线程中,要启动分线程的RunLoop,NSTimer才能执行。因为分线程的RunLoop是默认关闭的。

  NSTimer *timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(update) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

四、RunLoop常用的两种模式

a、NSDefaultRunLoopMode,默认模式,主线程中的RunLoop默认是NSDefaultRunLoopMode
b、UITrackingRunLoopMode,在滚动式图的情况下RunLoop处于此模式下。常见的场景为TableView、CollectionView、ScrollView的滑动对定时器的影响。
场景分析:
由于一个RunLoop不能同时使用两个RunLoopMode,所以当视图滚动的时候,RunLoop从默认模式的NSDefaultRunLoopMode跳转到UITrackingRunLoopMode。由于定时器还是NSDefaultRunLoopMode模式,所以会停止。我们只要把定时器的RunLoop的模式设定为NSRunLoopCommonModes(占位Mode)即可。

五、常用的使用场景

a、异步线程下下载图片,如果失败该怎么处理呢?
在此异步线程中启动一个RunLoop重新发送网络请求,下载图片。
b、需要执行一个耗时操作,该怎么处理?
开启一个异步子线程,启动它的RunLoop来执行该耗时操作。
c、在分线程中开启一个异步请求,会有什么问题?
我们需要判断请求是否结束,如果没有结束,要保持线程一直启动,直道结束的时候自动关闭。

//创建一个线程,调用NSTimer事件
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(update) object:nil];
    // 设置线程的优先级(0.0 - 1.0,1.0最高级)
    thread.threadPriority = 1;
    // 开启线程
    [thread start];
- (void)update{
    NSLog(@"----------分线程线程的定时器启动:%@",[NSThread currentThread]);
    
    @autoreleasepool{
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(newThing) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        
    //在分线程中如果不开启RunLoop,那么定时器是无法执行的
//    NSRunLoop *loop = [NSRunLoop currentRunLoop];
//    [loop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
//
//    [loop run];
    }
}
未开启分线程RunLoop.png
开启分线程RunLoop.png
上一篇下一篇

猜你喜欢

热点阅读