iOS高级技术:NSRunLoop须知(面试必备)

2017-11-10  本文已影响32人  biyuhuaping

什么是RunLoop

从字面意思看,就是运行循环,兜圈圈儿。

基本作用

1、保持程序的持续运行,接受用户输入。
2、处理APP中的各种事件(如触摸事件、定时器事件、Selector事件)
3、节省CPU资源,提高程序性能:该做事时做事,该休息时休息。
4、调用解耦。

RunLoop内部实现

其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)。

void message(int num) {
    printf("执行第%i个任务", num);
}

int main(int argc, const char * argv[]) {
    do {
        printf("有事吗? 没事我睡了");
        int number;
        scanf("%i", &number);
        message(number);
    } while (1);
    return 0;
}

iOS 中有2套API来访问和使用RunLoop

NSRunLoop 和 CFRunLoopRef都代表着RunLoop对象
NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要研究CFRunLoopRef层面的API(Core Foundation层面)。

获得RunLoop对象

Foundation

[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

Core Foundation

CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象

RunLoop与线程

每条线程都有唯一的一个与之对应的RunLoop对象。 主线程的RunLoop已经创建好了,子线程的RunLoop需要主动创建。
RunLoop在第一次获取时创建,在线程结束时销毁。

RunLoop的结构

[图片上传失败...(image-e41dd9-1510322280020)]

Core Foundation 中关于RunLoop的5个类

CFRunLoopRef
CFRunLoopModeRef
CFRunLoopTimerRef
CFRunLoopObserveRef
CFRunLoopSource

打印activity,查看RunLoop运行状态

// 1.创建Observer
// 第一个参数:用于分配该observer对象的内存
// 第二个参数:用以设置该observer所要关注的的事件
// 第三个参数:用于标识该observer是在第一次进入run loop时执行, 还是每次进入run loop处理时均执行
// 第四个参数:用于设置该observer的优先级
// 第五个参数: observer监听到事件时的回调block
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch(activity)
        {
            case kCFRunLoopEntry:
                NSLog(@"即将进入loop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理timers");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理sources");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"刚从休眠中唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"即将退出loop");
                break;
            default:
                break;
        }
    });
    
//     2.添加监听
    /*
     第一个参数: 给哪个RunLoop添加监听
     第二个参数: 需要添加的Observer对象
     第三个参数: 在哪种模式下监听
     */
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);
    
//     3,释放observer
    CFRelease(observer);

RunLoop事件队列

每次运行run loop,你线程的run loop对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:


RunLoop事件队列

RunLoopRunLoop的应用

NSTimer

设置RunLoopMode,让NSTimer不影响其他刷新,默认情况下NSTimer被加入NSDefalutRunLoopMode

如果不想让NSTimer受到组件或者动画影响,就添加到NSRunLoopCommonModes:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(ddd) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

常驻线程

AFNetWorking 中创建RunLoop,创建一个常驻服务线程的很好的方法

[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活着

[runLoop run];

自动释放池

activities = 0x1 = 1
1: 即将进入RunLoop : 创建一个自动释放池
activities = 0xa0 = 160 = 128 + 32
32:即将休眠 : 释放上一次的自动释放池, 创建一个新的自动释放池
128:即将退出RunLoop : 释放自动释放池

让Crash的APP回光返照,接到Crash的Signal后手动重启RunLoop

CFRunLoopRef runloop = CFRunLoopGetCurrent();
NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));
while(1){
for (NSString *mode in allModes){
    CFRunLoopInMode((CFStringRef)mode,0.001,false);
}}

一个TableView延迟加载图片的新思路

[self.avatarImageView performSelector:@selector(serImage:) withObjetc:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];

+ (NSThread *)networkRequestThread {
    static NSThread *networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [networkRequestThread start];
    });
    
    return networkRequestThread;
}
上一篇下一篇

猜你喜欢

热点阅读