iOS RunLoop 基本概念以及使用场景
2017-05-04 09:50
369 查看
一、RunLoop概念:
一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出。
实现这种模型的关键点在于:如何管理事件/消息,如何让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面
Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
二、RunLoop与线程的关系:
首先,iOS 开发中能遇到两个线程对象:
pthread_t 和 NSThread。过去苹果有份文档标明了 NSThread 只是
pthread_t 的封装,但那份文档已经失效了,现在它们也有可能都是直接包装自最底层的 mach thread。苹果并没有提供这两个对象相互转换的接口,但不管怎么样,可以肯定的是 pthread_t 和 NSThread 是一一对应的。比如,你可以通过 pthread_main_thread_np() 或 [NSThread mainThread] 来获取主线程;也可以通过 pthread_self() 或 [NSThread currentThread] 来获取当前线程。CFRunLoop 是基于 pthread
来管理的。
注意:苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain()
和 CFRunLoopGetCurrent()。 这两个函数内部的逻辑大概是下面这样
RunLoop 的核心就是一个 mach_msg()
,RunLoop 调用这个函数去接收消息,如果没有别人发送 port 消息过来,内核会将线程置于等待状态。例如你在模拟器里跑起一个 iOS 的 App,然后在 App 静止时点击暂停,你会看到主线程调用栈是停留在 mach_msg_trap() 这个地方。
自动释放池就是根据runloop的原理实现的
回到开始的疑问,为什么要使用RunLoop,一般情况下我们是没必要去启动线程的RunLoop,除非需要在一个单独的线程长久的检测某个事件,类似微信的语音功能,见一个RunLoop专门负责监听说话的线程。看需求而定了。
1.每条线程都有唯一的一个与之对应的RunLoop对象
2.主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
3.RunLoop在第一次获取时创建,在线程结束时销毁
4.获取RunLoop对象:
1)Foundation:
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
2)Core
Foundation:
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象
三、RunLoop使用场景:
苹果官方文档说明run loop的开启是运用在需要和线程有更多交互的场合上的。
四、概念:
1)Foundation 框架 ——>NSRunLoop
2)Core Foundation ——>CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象
NSRunLoop是基于CFRunLoopRef的一层OC包装, 所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API (Core Foundation 层面)
五、RunLoop相关类
CoreFoundation中关于RunLoop的5个类
1)CFRunLoopRef ——>NSRunLoop是基于这个类进行封装的
2)CFRunLoopModeRef ——>代表RunLoop的运行模式
一个 RunLoop包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入,这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
系统默认注册了5个Mode:
kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode 影响
UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
3)CFRunLoopSourceRef
4)CFRunLoopTimerRef
5)CFRunLoopObserverRef
六、RunLoop应用
1.NSTimer
2.ImageView显示
3.PerformSelector
4.常驻线程
5.自动释放池
一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出。
实现这种模型的关键点在于:如何管理事件/消息,如何让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面
Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
二、RunLoop与线程的关系:
首先,iOS 开发中能遇到两个线程对象:
pthread_t 和 NSThread。过去苹果有份文档标明了 NSThread 只是
pthread_t 的封装,但那份文档已经失效了,现在它们也有可能都是直接包装自最底层的 mach thread。苹果并没有提供这两个对象相互转换的接口,但不管怎么样,可以肯定的是 pthread_t 和 NSThread 是一一对应的。比如,你可以通过 pthread_main_thread_np() 或 [NSThread mainThread] 来获取主线程;也可以通过 pthread_self() 或 [NSThread currentThread] 来获取当前线程。CFRunLoop 是基于 pthread
来管理的。
注意:苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain()
和 CFRunLoopGetCurrent()。 这两个函数内部的逻辑大概是下面这样
RunLoop 的核心就是一个 mach_msg()
,RunLoop 调用这个函数去接收消息,如果没有别人发送 port 消息过来,内核会将线程置于等待状态。例如你在模拟器里跑起一个 iOS 的 App,然后在 App 静止时点击暂停,你会看到主线程调用栈是停留在 mach_msg_trap() 这个地方。
自动释放池就是根据runloop的原理实现的
回到开始的疑问,为什么要使用RunLoop,一般情况下我们是没必要去启动线程的RunLoop,除非需要在一个单独的线程长久的检测某个事件,类似微信的语音功能,见一个RunLoop专门负责监听说话的线程。看需求而定了。
1.每条线程都有唯一的一个与之对应的RunLoop对象
2.主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
3.RunLoop在第一次获取时创建,在线程结束时销毁
4.获取RunLoop对象:
1)Foundation:
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
2)Core
Foundation:
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象
三、RunLoop使用场景:
苹果官方文档说明run loop的开启是运用在需要和线程有更多交互的场合上的。
四、概念:
1)Foundation 框架 ——>NSRunLoop
2)Core Foundation ——>CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象
NSRunLoop是基于CFRunLoopRef的一层OC包装, 所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API (Core Foundation 层面)
五、RunLoop相关类
CoreFoundation中关于RunLoop的5个类
1)CFRunLoopRef ——>NSRunLoop是基于这个类进行封装的
2)CFRunLoopModeRef ——>代表RunLoop的运行模式
一个 RunLoop包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入,这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
系统默认注册了5个Mode:
kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode 影响
UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
3)CFRunLoopSourceRef
4)CFRunLoopTimerRef
5)CFRunLoopObserverRef
六、RunLoop应用
1.NSTimer
2.ImageView显示
3.PerformSelector
4.常驻线程
5.自动释放池
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) dispatch_source_t timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // // NSRunLoop 主线程对应的RunLoop对象 // NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop]; // NSLog(@"mainRunLoop = %@", mainRunLoop); // // NSRunLoop 获得当前方法所在线程对应的RunLoop // NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; // NSLog(@"currentRunLoop = %@", currentRunLoop); // // CFRunLoopRef 主线程对应的RunLoop对象 // CFRunLoopRef cfMainRunLoop = CFRunLoopGetMain(); // NSLog(@"cfMainRunLoop = %@", cfMainRunLoop); // // CFRunLoopRef 获得当前方法所在线程对应的RunLoop // CFRunLoopRef cfCurrentRunLoop = CFRunLoopGetCurrent(); // NSLog(@"cfCurrentRunLoop = %@", cfCurrentRunLoop); // // 开启一条子线程 // NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; // [thread start]; // 创建Observer /** * 参数1: 指定如果给Observer分配存储空间 * 参数2: 需要监听的状态类 * kCFRunLoopEntry = (1UL << 0), 即将启动(进入)的时候 * kCFRunLoopBeforeTimers = (1UL << 1), 即将处理timer事件 * kCFRunLoopBeforeSources = (1UL << 2), 即将处理source事件 * kCFRunLoopBeforeWaiting = (1UL << 5), 即将进入睡眠 * kCFRunLoopAfterWaiting = (1UL << 6), RunLoop被唤醒 * kCFRunLoopExit = (1UL << 7), RunLoop退出 * kCFRunLoopAllActivities = 0x0FFFFFFFU 监听所有状态 * */ CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { switch (activity) { case kCFRunLoopEntry: NSLog(@"即将进入RunLoop"); break; case kCFRunLoopBeforeTimers: NSLog(@"即将处理timer"); break; case kCFRunLoopBeforeSources: NSLog(@"即将处理source"); break; case kCFRunLoopBeforeWaiting: NSLog(@"即将进入睡眠"); break; case kCFRunLoopAfterWaiting: NSLog(@"RunLoop刚从睡眠中唤醒"); break; case kCFRunLoopExit: NSLog(@"RunLoop即将退出"); break; default: break; } }); // 给主线程的RunLoop添加一个观察者,要监听的是RunLoop的哪种运行模式 /** * 参数1: 需要给哪个RunLoop添加观察者 * 参数2: 需要添加的Observer对象 * 参数3: 在哪种模式下可以监听 kCFRunLoopDefaultMode == NSDefaultRunLoopMode */ CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode); [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES]; } - (void)show{ NSLog(@"-------------%s", __func__); } - (void)run { // 注意: 如果想给子线程添加RunLoop, 不能直接alloc init // [[NSRunLoop alloc] init]; // 错误 // 只要调用currentRunLoop方法, 系统就会自动创建一个RunLoop, 添加到当前线程中 [NSRunLoop currentRunLoop]; // 这个方法是懒加载 }
相关文章推荐
- IOS RunLoop详解以及API使用
- 分布式(集群)的基本概念以及分布式的应用场景【转】
- IOS学习笔记(七)之UISegmentedControl分段控件的基本概念和使用方法
- iOS学习笔记----NSTimer(基本使用,DefaultRunLoopMode,NSRunLoopCommonModes,准确性)
- iOS容易造成循环引用的三种场景NSTimer以及对应的使用方法(一)
- (转)iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等
- MS BI 中的Ad - hoc 报表 (即席报表) 基本概念以及如何创建和使用
- iOS多线程编程(四)NSRunLoop初步概念以及NSTimer在NSThread中的使用
- IOS下的 NSTimer与Run loop Modes的使用和区别
- iOS开发OC基础:OC集合NSSet、NSMutableSet以及NSCountedSet的基本方法的使用
- iOS 分类的基本使用(更改frame)以及全局变量.pch的使用
- ios多线程的几种创建方式以及基本使用
- IOS学习笔记(八)之UIActivityIndicatorView(活动指示器视图)的基本概念和使用方法
- 分布式(集群)的基本概念以及分布式的应用场景
- MS BI 中的Ad - hoc 报表 (即席报表) 基本概念以及如何创建和使用
- IOS学习笔记(七)之UISegmentedControl分段控件的基本概念和使用方法
- IOS学习笔记(九)之UIAlertView(警告视图)和UIActionSheet(操作表视图)基本概念和使用方法
- IOS学习笔记(九)之UIAlertView(警告视图)和UIActionSheet(操作表视图)基本概念和使用方法
- iOS Run loop使用实例(★好文章firecat推荐★)
- iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等