顧名思義, Runloop就是運行循環, 在程序運行過程當中循環作一些事情bash
應用範疇網絡
一個OC程序, main
函數是這樣的app
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
複製代碼
Runloop
, main
函數返回0
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return 0;
}
}
複製代碼
Runloop
的僞代碼, 以下圖所示do-while
是一個死循環, 當沒有任何消息發生的時候, 程序處於睡眠狀態等待消息發生RunLoop的基本做用
保持程序的持續運行
處理App中的各類事件(好比觸摸事件、定時器事件等)
節省CPU資源,提升程序性能:該作事時作事,該休息時休息
......
複製代碼
Foundation
和Core Foundation
來獲取RunLoop
[NSRunLoop currentRunLoop];
複製代碼
[NSRunLoop mainRunLoop];
複製代碼
CFRunLoopGetCurrent()
複製代碼
CFRunLoopGetMain()
複製代碼
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
複製代碼
CFRunLoopRef
實際類型是__CFRunLoop
typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
};
複製代碼
_modes
中存放的是CFRunLoopModeRef
類型數據, 其中就有_currentMode
, 只不過_currentMode
是當前使用的mode
函數
CFRunLoopModeRef
的結構以下oop
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
};
複製代碼
_sources0
和_sources1
是CFRunLoopSourceRef
類型數據_observers
是CFRunLoopObserverRef
類型數據_timers
是CFRunLoopTimerRef
類型數據CFRunLoopModeRef
表明RunLoop
的運行模式RunLoop
包含若干個Mode
,每一個Mode
又包含若干個Source0/Source1/Timer/Observer
RunLoop
啓動時只能選擇其中一個Mode
,做爲currentMode
Mode
,只能退出當前Loop
,再從新選擇一個Mode
進入
Source0/Source1/Timer/Observer
能分隔開來,互不影響Mode
裏沒有任何Source0/Source1/Timer/Observer
,RunLoop
會立馬退出kCFRunLoopDefaultMode
(NSDefaultRunLoopMode
): App
的默認Mode
,一般主線程是在這個Mode
下運行UITrackingRunLoopMode
: 界面跟蹤 Mode
,用於 ScrollView
追蹤觸摸滑動,保證界面滑動時不受其餘 Mode
影響Source0
處理的RunLoop
添加Observer
的方式監聽RunLoop
的狀態, 使用下面這個函數/** 給RunLoop添加Observer @param rl 目標RunLoop @param observer 須要添加的Observer @param mode 監聽狀態 */
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFRunLoopMode mode);
複製代碼
Observer
/**
建立Observer
@param allocator 分配器
@param activities 須要監聽的狀態
@param repeats 是否重複監聽
@param order 順序
@param callout 回調函數
@param context 附加對象
@return 建立好的Observer
*/
CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context);
複製代碼
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
};
複製代碼
Observer
, 並將其添加到Runloop
中, 監聽屏幕點擊事件RunLoop
的狀態, 當最後沒有事件時, Runloop
進入睡眠狀態sources
狀態, 而後執行點擊事件監聽UITextView
的滾動, 查看RunLoop
的currentMode
性能
建立Observer
的另外一種方式, 使用block
監聽RunLoop
狀態ui
view
上添加一個UITextView
UITextView
, 有以下打印kCFRunLoopDefaultMode
, 進入UITrackingRunLoopMode
UITrackingRunLoopMode
, 進入kCFRunLoopDefaultMode