iOS 理解runLoop
RunLoop的使用及理解
1. RunLoop的基本作用
1.保證程式的持續執行 2.處理app中的各種事件(觸控事件、定時事件、selector事件) 3.節省CPU資源,提高程式效能,做該做的事,休息的時候休息
2. RunLoop相當於一個死迴圈
int main(int argc, const char * argv[]) { BOOL running = YES; do { /**執行各種操作*/ }while(running); }
在程式進入main函式後,預設就開啟一個類似死迴圈,確保程式一直在執行不退出的狀態
int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class])); } } 備註:該函式屬於程式的一開始啟動就會呼叫的函式入口
3.runLoop共有兩套API介面
a. Foundation框架NSRunLoop
b. Core Foundation框架CFRunLoopRef
特徵:NSRunLoop
和CFRunLoopRef
都代表著RunLoop
物件,它們是等價的,可以互相轉換
NSRunLoop
是基於CFRunLoopRef
的一層OC包裝,所以要了解RunLoop
內部結構,需要多研究CFRunLoopRef
層面的API(Core Foundation層面)
4.蘋果官網
ofollow,noindex">蘋果官網連線解釋
5.Runloop與執行緒
1.RunLoop與執行緒的關係
a. Runloop和執行緒的關係:一個Runloop對應著一條唯一的執行緒 b. Runloop的建立:主執行緒Runloop已經建立好了,子執行緒的runloop需要手動建立 c. Runloop的生命週期:在第一次獲取時建立,線上程結束時銷燬
2.如何獲得當前Runloop物件
1. NSRunLoop * runloop1 = [NSRunLoop currentRunLoop]; 2. CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
3.如何拿到當前應用程式的主Runloop
1. NSRunLoop * runloop1 = [NSRunLoop mainRunLoop]; 2. CFRunLoopRef runloop2 = CFRunLoopGetMain();
注意:開一個子執行緒建立runloop,不是通過alloc init方法建立,而是直接通過呼叫currentRunLoop方法來建立,它本身是一個懶載入的。
在子執行緒中,如果不主動獲取Runloop的話,那麼子執行緒內部是不會建立Runloop的。可以下載CFRunloopRef的原始碼,搜尋_CFRunloopGet0,檢視程式碼。
Runloop物件是利用字典來進行儲存,而且key是對應的執行緒Value為該執行緒對應的Runloop。
Runloop要想跑起來,它的內部必須要有一個mode,這個mode裡面必須有source\observer\timer,至少要有其中的一個
CFRunloopModeRef
1.CFRunloopModeRef代表著Runloop的執行模式 2.一個Runloop中可以有多個mode,一個mode裡面又可以有多個source\observer\timer等等 3.每次runloop啟動的時候,只能指定一個mode,這個mode被稱為該Runloop的當前mode 4.如果需要切換mode,只能先退出當前Runloop,再重新指定一個mode進入 5.這樣做主要是為了分割不同組的定時器等,讓他們相互之間不受影響 6.系統預設註冊了5個mode
CFRunloopTimerRef
1.runloop一啟動就會選中一種模式,當選中了一種模式之後其它的模式就都不鳥。一個mode裡面可以新增多個NSTimer,也就是說以後當建立NSTimer的時候,可以指定它是在什麼模式下執行的 2.它是基於時間的觸發器,說直白點那就是時間到了我就觸發一個事件,觸發一個操作。基本上說的就是NSTimer
相關程式碼
- (void)timers { /**NSTimer呼叫了scheduledTimer方法,那麼會自動新增到當前的runloop裡面去,而且runloop的執行模式kCFRunLoopDefaultMode*/ NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; /**更改模式*/ [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } - (void)timer1 { [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; /**定時器新增到UITrackingRunLoopMode模式,一旦runloop切換模式,那麼定時器就不工作*/ [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; /**定時器新增到NSDefaultRunLoopMode模式,一旦runloop切換模式,那麼定時器就不工作*/ [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; } - (void) run { NSLog(@"---run---%@",[NSRunLoop currentRunLoop].currentMode); } - (IBAction)btnClick { NSLog(@"---btnClick---"); }