您的位置:首页 > 运维架构

NSRunLoop学习笔记

2016-03-09 09:38 302 查看
内容是自己学习笔记,来源于互联网

RunLoop简介

基本作用

保持程序的持续运行,相当于一个do while循环,程序相当于一个死循环,一直在循环内做事情。程序启动时已经启动了一个runLoop,所以程序不会直接退出。是在main函数启动的,和主线程相关.

处理APP的各种事件:触摸,定时器,selector事件,事件触发的时候,runLoop会按步骤执行事件。

节省CPU的资源,提升程序性能,合理分配工作和休眠时间,在没有操作任务的时候会进入休眠,有任务到来会唤醒.

runLoop对象

iOS 两套方案访问runLoop

Foundation -> NSRunLoop

Core Foundation -> CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表RunLoop对象。NSRunLoop是基于CFRunLoopRef的一层OC的包装,CFRunLoopRef是RunLoop底层API.

RunLoop与线程的关系

每条线程都有唯一的一个与之对应的RunLoop对象.

主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建

RunLoop 在第一次获取时候创建,在线程结束时候销毁.

获取RunLoop对象的方法

Foundation

[NSRunLoop mainRunLoop];
[NSRunLoop currentRunLoop];


CFRunLoopRef

CFRunLoopGetCurrent();
CFRunLoopGetMain();


RunLoop相关类

CFRunLoopRef ;//
CFRunLoopSourceRef;//source
CFRunLoopTimerRef;//定时器
CFRunLoopObserverRef;//观察者
CFRunLoopModeRef;//这个类没有外漏


CFRunLoopModeRef

CFRunLoopModeRef表示RunLoop的运行模式.

一个RunLoop可以包含若干个Mode,一个Mode 包含不同的若干个source,timer,observer。

每次RunLoop启动只能指定其中一种模式,可以通过curreMode方法获取

切换mode只能退出Loop,重新再指定一个Mode进入,这样可以分开不同模式下的source,timer,observer

CFRunLoopModeRef以供有5个,其中有两个用不到一个是UIInitializationRunLoopMode 是刚刚进入程序的时候进入的第一个,启动完成后就退出了,还有一个GSEventReceiveRunLoopMode,是系统内部的,也用不到,而且代码根本打不出来,所以可以忽略.

kCFRunLoopCommonModes; //kCFRunLoopDefaultMode|UITrackingRunLoopMode
kCFRunLoopDefaultMode;//默认模式,app启动后的模式,主线程就是这个模式
UITrackingRunLoopMode;//界面跟踪模式,追踪触屏滑动,保证界面滑动时候不受其他mode影响


CFRunLoopSourceRef

CFRunLoopSourceRef表示的是事件的输入源。

分类1:

- Port-Based Source 基于端口的,内核或者其他线程发过来的信息

- Custom Input Source 自定义的,一般不用

- Cocoa perform selector sources 通过selector消息选择器发送的事件

分类2:

- source0 :非基于port的

- source1 :基于内核的和其他线程通信,接受分发系统事件.

CFRunLoopTimerRef

就是NSTimer,定时器.

CFRunLoopObserverRef

可以监听状态runLoop状态变化的观察者.监听runLoop包含下面的状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),//进入runLoop
kCFRunLoopBeforeTimers = (1UL << 1),//即将处理timer事件
kCFRunLoopBeforeSources = (1UL << 2),//即将处理source
kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6),//刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7),//runLoop退出了
kCFRunLoopAllActivities = 0x0FFFFFFFU//所有的状态
};


runLoop处理逻辑

官方版本



网络版本



runLoop应用

定时器

NSTimer定时器的创建方式

第一种:

// 调用了scheduledTimer返回的定时器,已经自动被添加到当前runLoop中,而且是NSDefaultRunLoopMode
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

// 修改模式
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


第二种:创建一个纯净的定时器,需要自己手动设置运行模式

NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 定时器只运行在NSDefaultRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作
//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

// 定时器只运行在UITrackingRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作
//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

// 定时器会跑在标记为common modes的模式下
// 标记为common modes的模式:UITrackingRunLoopMode和NSDefaultRunLoopMode
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];


在runLoop状态变化时候做事情

// 创建observer
//第一个参数表示如何给observe分配空间,CFAllocatorGetDefault,表示用默认的空间分配器
//第二个参数表示监听的是什么状态,可以检测一种也可以检测所有的
//YES 表示不是监听一次,而是每次通过这个runLoop的时候都监听
//0 位置的参数表示设定优先级,用于多个观察者同时监听一个runLoop的时候,数字越小,优先级越高,默认写0就可以了
//后面的块,可以打印相关的状态
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
});
// 添加观察者:监听RunLoop的状态
//第一个参数.获取添加观察者的runLoop
//第二个参数.添加观察者对象
//第三个参数.要监听的模式
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

// 释放Observer
CFRelease(observer);


imageView显示

// 只在NSDefaultRunLoopMode模式下显示图片
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];


可以解决tableView或者scrollView滑动时候卡顿问题,让图片仅仅在不滑动的时候加载.提升用户体验.

创建不死线程

默认状态下线程执行完操作就死亡了,要创建一个不死线程要用runLoop。

实现策略:

创建一个线程:

self.thread = [[XMGThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[self.thread start];


在线程的run方法里面,添加代码启动新创建的线程的runLoop,

runLoop的run方法,运行的时候如果发现运行模式为空会直接退出,

runLoop不可以没有source,timer,observer.如果3个都没有,就会退出.

所以必须要添加一个保证不退出。

[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];


调用run方法相当下面的情况的一种,都是一致运行到一个非常大的日期,保证不会退出.创造一个死循环.

// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];


runLoop循环,不会像do while循环卡死,而是一致在不断的运行着,只有当事件触发的时候才会响应时间,没有事件就会休眠.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: