/********************************************************************************************
* author:conowen@大钟
* E-mail:conowen@hotmail.com
* http://blog.csdn.net/conowen
********************************************************************************************/
1、RunLoop定义
void CFRunLoopRun(void) { /* DOES CALLOUT */
int32_t result;
do {//就是一个do while循环
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
Boolean did = false;
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
CFRunLoopModeRef previousMode = rl->_currentMode;
rl->_currentMode = currentMode;
int32_t result = kCFRunLoopRunFinished;
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopPopPerRunData(rl, previousPerRun);
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
2、Runloop的工作模式
Core Foundation框架: CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象,NSRunLoop是基于CFRunLoopRef的一层OC封装而已。
//获得RunLoop对象
//Foundation NSRunLoop
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
//Core Foundation <span style="font-family: SimSun;">NSRunLoop</span>
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象

-
当RunLoop的准备运行的时候
-
当RunLoop准备处理一个Timer sources的时候
-
当RunLoop准备处理一个input sources的时候
-
当RunLoop准备休眠的时候
-
当RunLoop被唤醒时,准备执行这个事件的时候
- 当RunLoop准备退出的时候
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
3、RunLoop的Mode
Default | | The default mode is the one used for most operations. Most of the time, you should use this mode to start your run loop and configure your input sources. Default模式,一般情况下应使用此Mode。主线程RunLoop启动的就是默认模式 |
Connection | | Cocoa uses this mode in conjunction with 使用这个Mode来监控NSConnection对象的回复,用户基本不会使用此Mode。 |
Modal | | Cocoa uses this mode to identify events intended for modal panels. 使用这个Mode来处理modal panels的事件 |
Event tracking | | Cocoa uses this mode to restrict incoming events during mouse-dragging loops and other sorts of user interface tracking loops. 处理用户的一些拖动事件,如UIScrollView的滚动 |
Common modes | | This is a configurable group of commonly used modes. Associating an input source with this mode also associates it with each of the modes in the group. For Cocoa applications, this set includes the default, modal, and event tracking modes by default. Core Foundation includes just the default mode initially. You can add custom modes to the set using theCFRunLoopAddCommonMode funtion. 事实上这并不是一个Mode,这只是有关联关系的“Mode”,像一个“标识”,如果设置RunLoop的Mode为这个模式,就可以把Sources同时添加到RunLoop的 default、modal、event tracking模式中(下面用一个场景解释这个到底有啥用) |
获取当前线程的RunLoop Mode
NSString* runLoopMode = [[NSRunLoop currentRunLoop] currentMode];
4、界面滚动的时候为什么NSTimer会失效
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]
//直接把NSTimer添加到Event Tracking模式中
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//设置Common Modes,把NSTimer同时添加到defaul、modal、Event Tracking模式中
因为RunLoop一次只能执行一个Mode(包含各种Sources),所以把NStimer添加到与滚动事件所在的Mode就行,或者重新开一个线程(不同的RunLoop)。