iOS的NSRunLoop详解
最开始问大家几个问题:
1.应用程序在启动的时候是如何响应用户的手势操作呢?
2.主线程可以相应哪些事件呢?新开辟的一个子线程可以响应用户的滑动手势吗?
引入NSRunloop
NSRunLoop是iOS的CoreFoundation的一部分,Foundation对Core Foundation又做了一层封装。
每一个NSThread里边都有一个NSRunLoop,NSRunloop是一个响应事件处理的循环,当有事件传入的时候,执行,没有事件传入的时候,等待。一般来说我们不需要手动创建和启动NSRunloop。NSRunloop与线程是相互依存的关系
NSRunloop响应的事件包括两类:一是来自Input sources的异步事件,一是来自Timer sources的同步事件。
1.NSRunloop在一个线程中是一个单例
可以用[NSRunloop currentRunloop]获取单例
2.NSRunloop的启动
一般来说可以用:[[NSRunloop currentRunloop]run];来启动
3.NSRunloopMode
Default模式
定义:NSDefaultRunLoopMode(Cocoa)kCFRunLoopDefaultMode(Core Foundation)
描述:默认模式中几乎包含了所有输入源(NSConnection除外),一般情况下应使用此模式。
Connection模式
定义:NSConnectionReplyMode(Cocoa)
描述:处理NSConnection对象相关事件,系统内部使用,用户基本不会使用。
Modal模式
定义:NSModalPanelRunLoopMode(Cocoa)
描述:处理modal panels事件。
Event tracking模式
定义:UITrackingRunLoopMode(iOS) NSEventTrackingRunLoopMode(cocoa)
描述:在拖动loop或其他user interface tracking loops时处于此种模式下,在此模式下会限制输入事件的处理。例如,当手指按住 UITableView拖动时就会处于此模式。
Common模式
定义:NSRunLoopCommonModes(Cocoa)kCFRunLoopCommonModes(Core Foundation)
描述:这是一个伪模式,其为一组run loop mode的集合,将输入源加入此模式意味着在Common Modes中包含的所有模式下都可以 处理。在Cocoa应用程序中,默认情况下Common Modes包含default modes,modal modes,event Tracking modes.可使 用CFRunLoopAddCommonMode方法想Common Modes中添加自定义modes。
3.currentMode属性
currentMode指的是该线程现在所处的运行模式
RunLoop在某一时刻只能且必须在一种特定运行模式下执行
更换Mode时,需要停止当前Loop,然后重启新Mode
Mode是iOS滑动顺畅的关键
4.一个线程可以处理多个RunloopMode的事件源
[[NSRunloop currentRunloop]addTimer: forRunloopMode:];
[[NSRunloop currentRunloop]addSelector: forRunloopMode:];
5.NSRunloop处于某个运行模式的时候,就会执行该运行模式下的所有的事件处理
比如用户滑动屏幕,那么操作系统会将NSRunloop切换到UITrackingRunLoopMode运行模式下,该运行模式对应的方法都会被执行
6.切换RunloopMode
目前切换RunloopMode是由操作系统来操作,不允许程序员手动调用
NSRunloop的用途
1.解决NSURLConnection在用户滚动UIScrollView或者UITableView不执行的问题。
当使用NSURLConnection来加载文件的时候,如下面的代码:
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self startImmediately:NO];
[connection start];
NSURLConnection默认运行在default mode下,这样当用户在拖动UITableView处于UITrackingRunLoopMode模式时, NSURLConnection的数据也无法处理。
通过下面的方法可以解决这个问题:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
2.在后台线程运行NSURLConnection
通过CFRunLoopRun()使得后台线程一直执行,使用CFRunLoopStop(CFRunLoopGetCurrent())结束。