目錄
Runloop--概念
基本作用:
- 保持程序的持續運行
- 處理App中的各種事件(比如觸摸事假、定時事件、selector事件)
- 節省CPU資源,提高程序性能:該做事時做事,改休息時休息。
iOS中有2套API來訪問和使用Runloop:
- Foundation NSRunloop
- Core Foundation CFRunLoopRef
Runloop--獲取Runloop對象
- Foundation
[NSRunloop currentRunLoop];//獲取當前線程的Runloop對象
[NSRunloop mainRunLoop];//獲取主線程的Runloop對象
- Core Foundation
CFRunloopGetCurrent();//獲取當前線程的Runloop對象
CFRunLoopGetMain();//獲取主線程的Runloop對象
- 互相轉化方法
mainRunLoop.getCFRunLoop
Runloop--與線程的關係
每條線程都有唯一的一個與之對應的Runloop對象
主線程的Runloop已經自動創建好了,子線程的Runloop需要手動創建
Runloop在第一次獲取時創建,在線程結束時銷燬
Runloop--五大相關類
Core Foundation 中關於 Runloop的5個類
- CFRunLoopRef//本身
- CFRunLoopModeRef//運行模式
- CFRunLoopSourceRef//事件源輸入源
- CFRunloopTimerRef//定時器
- CFRunLoopObserverRef//監聽
CFRunLoopModeRef(運行模式)
CFRunLoopModeRef代表RunLoop的運行模式
- 一個Runloop包含若干個Mode,每個Mode又包含若干個Source/Timer/Observer
- 每次Runloop啓動時,只能指定其中一個 Mode,這個Mode被稱爲CurrentMode
- 如果需要切換Mode,只能退出Loop,再重新指定一個Mode進入
- 這樣做主要是爲了分隔開不同組的Source/Timer/Observer,讓其互不影響
系統默認註冊了5個Mode:
- kCFRunLoopDefaultMode:App默認Mode,通常主線程是在這個Mode下運行
- UITrackingRunLoopMode:界面跟蹤Mode,用於ScrollView追蹤觸摸滑動,保證界面滑動時不受其他Mode影響
- UIIntiallizationRunLoopMode:在剛啓動App時進入的第一個Mode,啓動完成後就不再使用
- GSEventReceiveRunLoopMode:接受系統事件的內部Mode,通常用不到
- kCFRunLoopCommonModes:這是一個佔位用的Mode,不是一種真正的Mode
CFRunLoopSourceRef(輸入源)
是事件源(輸入源)
- Source0:非基於Port的(用戶主動觸發的事件,點擊按鈕,拖拽表格)
- Source1:基於Port的(系統內部的消息事件)
CFRunLoopTimerRef(定時器)
CFRunLoopTimerRef是基於時間的觸發器
基本上說的就是NSTimer
CFRunLoopObserverRef(觀察者)
是觀察者,能夠監聽RunLoop的改變狀態
//創建監聽者
/*
1.怎麼分配存儲空間
2.要監聽的狀態 kCFRunLoopAllActivities所有的狀態
3.是否持續監聽
4.優先級,總是傳0
5.當狀態改變時候回調
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
/*
kCFRunLoopEntry = (1UL << 0),即將進入runloop
kCFRunLoopBeforeTimers = (1UL << 1),即將處理timer事件
kCFRunLoopBeforeSources = (1UL << 2),即將處理source事件
kCFRunLoopBeforeWaiting = (1UL << 5),即將進入睡眠
kCFRunLoopAfterWaiting = (1UL << 6),被喚醒
kCFRunLoopExit = (1UL << 7),runloop退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"即將進入runloop");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"即將處理timer事件");
break;
case kCFRunLoopBeforeSources:
NSLog(@"即將處理source事件");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"即將進入睡眠");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"被喚醒");
break;
case kCFRunLoopExit:
NSLog(@"runloop退出");
break;
default:
break;
}
});
/*
1.要監聽哪個runloop
2.觀察者
3.運行模式
NSDefaultRunLoopMode = kCFRunLoopDefaultMode
NSRunLoopCommonModes = kCFRunLoopCommonModes
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}
Runloop--應用
NSTimer
ImageView顯示
PerformSelector
常駐線程
自動釋放池
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
Runloop--面試題
1.什麼是RunLoop?
從字面意思看是運行循環、跑圈
其實它內部就是do-while循環,在這個循環內部不斷地處理各種任務(比如Source、Timer、Observer)一個線程對應一個RunLoop,主線程的RunLoop默認已經開啓,子線程的RunLoop得手動啓動(調用runloop方法)
RunLoop只能選擇一個Mode啓動,如果當前Mode中沒有任何Source(Sources0、Sources1)、Timer,那麼就直接退出RunLoop
2.自動釋放池什麼時候釋放?
第一次創建:啓動runloop
最後一次銷燬:runloop退出的時候
其他時候創建和銷燬:當runloop即將睡眠的時候銷燬之前的釋放池,重新創建一個新的
3.在開發中如何使用RunLoop?什麼應用場景?
開啓一個常駐線程(讓一個子線程不進入消亡狀態,等待其他線程發來消息,處理其他事件)
可以控制定時器在特定模式下執行
可以讓某些事件(行爲、任務)在特定模式下執行
可以添加Observer 監聽RunLoop的狀態,比如監聽點擊事件的處理(在所有點擊事件之前做一些事情)
RunLoop--注意點
1.子線程runloop默認不創建
NSRunloop *loop= [NSRunloop currentRunLoop];//創建子線程runloop
[Loop run];//開啓runloop
2.在runloop中有多個運行模式,但是runloop只能選擇一種模式運行
3.mode裏面至少有一個timer或者source