1. 概念api
runloop是運動循環,不斷跑圈,無限循環框架
做用:
oop
保持程序的持續運行 (iOS程序一直活着的緣由)
性能
處理App中的各類事件(eg:觸摸事件/定時器事件/selector事件【選擇器·performSelector···】)spa
節省CPU資源,提升程序的性能(有事作事,沒事休息)
線程
程序已啓動,就開啓了一個runloop無限循環,所以程序才能持續的運行code
#import <UIKit/UIKit.h>#import "AppDelegate.h"int main(int argc, char * argv[]) {@autoreleasepool {return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}}
2. Runloop對象orm
1> 在iOS開發中有兩套api來訪問Runloopserver
Foundation框架【NSRunloop】(OC)對象
Core Foundation框架【CFRunloopRef】(C)
2> NSRunLoop和CFRunLoopRef都表明着RunLoop對象,它們是等價的,能夠互相轉換
3> NSRunLoop是基於CFRunLoopRef的一層OC包裝,因此要了解RunLoop內部結構,須要多研究CFRunLoopRef層面的API(Core Foundation層面)
3. Runloop與線程的關係
1> Runloop和線程的關係:一個Runloop對應着一條惟一的線程
問題:如何讓子線程不死
回答:給這條子線程開啓一個Runloop
2> Runloop的建立:主線程Runloop已經建立好了,子線程的runloop須要手動建立
3> Runloop的生命週期:在第一次獲取時建立,在線程結束時銷燬
1. Foundation框架【NSRunloop】建立Runloop對象
// 獲取當前線程下的Runloop, 懶加載的形式建立NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];// 獲取主線程下的RunloopNSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
2. Core Foundation框架【CFRunloopRef】建立Runloop對象
// 獲取當前線程下的Runloop, 懶加載的形式建立CFRunLoopRef runloop2 = CFRunLoopGetCurrent();// 獲取主線程下的RunloopCFRunLoopRef runloop2 = CFRunLoopGetMain();
3. Runloop運行原理圖
4. Runloop相關的類
CFRunloopRef
CFRunloopModeRef【Runloop的運行模式】
CFRunloopSourceRef【Runloop要處理的事件源】
CFRunloopTimerRef【Timer事件】
CFRunloopObserverRef【Runloop的觀察者(監聽者)】
Runloop要想跑起來,它的內部必需要有一個mode,mode中必須有source/observer/time,至少要有其中的一個
5. CFRunloopModeRef【Runloop的運行模式】
Runloop每次啓動的時候只能指定一個運行模型,切換模式時必須退出當前的Runloop,再從新進入一個mode,是爲了分割不一樣組的定時器互不影響
kCFRunLoopDefaultMode:App的默認Mode,一般主線程是在這個Mode下運行
UITrackingRunLoopMode:界面跟蹤 Mode,用於 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其餘 Mode 影響
UIInitializationRunLoopMode: 在剛啓動 App 時第進入的第一個 Mode,啓動完成後就再也不使用
GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,一般用不到
kCFRunLoopCommonModes: 這是一個佔位用的Mode,不是一種真正的Mode
6. CFRunloopTimerRef【Timer事件】
1> NSTimer
- (void)timer0{NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];/* NSDefaultRunLoopMode -> kCFRunLoopDefaultMode 默認模式主線程中執行 NSRunLoopCommonModes -> kCFRunLoopDefaultMode/UITrackingRunLoopMode UITrackingRunLoopMode -> 界面追蹤,其餘不工做 */[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];}
2. GCD定時器
GCD定時器必須必須保存起來才能使用
- (void)gcdTimer{NSLog(@"+++++++++");// 1.建立定時器dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));// 2.設置定時器/* 第一個參數:定時器 第二個參數:從哪一個時間開始 第三個參數:間隔時間 第四個參數:精確度, 0表明無偏差 */ dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);// 3.定時器觸發事件 dispatch_source_set_event_handler(timer, ^{NSLog(@"----------");});// 4.開啓定時器 dispatch_resume(timer);// GCD定時器建立是個局部變量須要保存才能執行 self.timer = timer;}
7. CFRunloopSourceRef【Runloop要處理的事件源】
(1)之前的分法
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources
(2)如今的分法
Source0:非基於Port的 (用戶觸發的時間)
Source1:基於Port的 (經過內核和其它線程相互發送消息)
8. CFRunloopObserverRef【Runloop的觀察者(監聽者)】
- (void)observer{// 建立一個觀察者/* 第一個參數:獲取內存的方式 第二個參數:監聽哪些狀態 第三個參數:是否持續監聽 第四個參數:0 第五個參數:block代碼塊 kCFRunLoopEntry = (1UL << 0), 準備進入 kCFRunLoopBeforeTimers = (1UL << 1), 即將處理timer事件 kCFRunLoopBeforeSources = (1UL << 2), 即將處理source事件 kCFRunLoopBeforeWaiting = (1UL << 5), 即將進入休眠 kCFRunLoopAfterWaiting = (1UL << 6), 喚醒 kCFRunLoopExit = (1UL << 7), 退出 kCFRunLoopAllActivities = 0x0FFFFFFFU 全部 */CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry:NSLog(@"準備進入");break;case kCFRunLoopBeforeTimers:NSLog(@"即將處理timer事件");break;case kCFRunLoopBeforeSources:NSLog(@"即將處理source事件");break;case kCFRunLoopBeforeWaiting:NSLog(@"即將進入休眠");break;case kCFRunLoopAfterWaiting:NSLog(@"喚醒");break;case kCFRunLoopExit:NSLog(@"退出");break;}});// 給runloop添加一個觀察者CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(show) userInfo:nil repeats:YES];// 釋放觀察者CFRelease(observer);}
9. Runloop運行邏輯