你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> iOS runloop

iOS runloop

編輯:關於IOS

寫這篇文章開始之前,我都不知道runloop是什麼東西,如果從字面的意思翻譯應該是一直循環的跑,懷疑可能和死鎖有關系,可是死鎖具體是怎麼回事,我只是記得有這個說法,也發現了一個自己不懂的知識。

初識runloop

我在網上看了一下@sunnnyxx 關於runloop的視頻.了解了一下runloop相關知識,也去網絡上看各種關於runloop的講述。

我們一般程序就是執行一個線程,是一條直線.有起點終點.而runloop就是一直在線程上面畫圓圈,一直在跑圈,除非切斷否則一直在運行。網上說的比喻很好,直線就像昙花一現一樣,圓就像OS,一直運行直到你關機為止。

在我們學習iOS生命周期裡面都會存在銷毀的過程,但是屏幕好像一直能接收各種指令,感覺很像runloop的功效,好像這些是和頂層UIKit無關,IOS架構最底層是Core OS,我分析應該是蘋果封裝好了,只是我們看不到源碼而已。

為什麼要使用runloop

@sunnnyxx 在視頻介紹了四個作用:

使程序一直運行接受用戶輸入
決定程序在何時應該處理哪些Event
調用解耦(對於編程經驗為0的完全沒搞懂這個意思,解釋為Message Queue)
節省CPU時間
這段視頻我覺得不太適合小白去看,因為好多概念還沒有融會貫通,也沒有理解透徹。但是既然看了,就得總結一下,至少產生一個樹突先,留下一個問號,未來把問號變成歎號。

回到開始的疑問,為什麼要使用RunLoop,一般情況下我們是沒必要去啟動線程的RunLoop,除非需要在一個單獨的線程長久的檢測某個事件,就像視頻裡面提到的類似微信的語音功能,見一個RunLoop專門負責監聽說話的線程。看需求而定了。

CFRunLoopSource

Source是RunLoop的數據源抽象類,類似IOS中的protocol
RunLoop定義兩個Version的Source
Source0:處理App內部事件,App自己負責管理(觸發),如UIEvent,CFSocket
Source1:由RunLoop和內核管理,Mach port驅動 如CFMach、CFMessage
CFRunLoopObserver

向內部報告RunLoop當前狀態的更改 CAAnimation
RunLoopObserver 與 Autorelease Pool

UIKit通過RunLoopObserver在RunLoop兩次Sleep間對AutoreleasePool進行pop和push,將這次Loop中產生的Autorelease對象釋放。(好像swift中沒有關於釋放的問題)
CFRunLoopMode

RunLoop在同一時段只能且必須在一種特定Mode下Run
更換Mode時, 需要暫停當前的Loop,然後重啟新的Loop
NSDefalutRunLoopMode      默認狀態.空閒狀態
UITrackingRunLoopMode     滑動ScrollView
UIInitializationRunLoopMode    私有,App啟動時
NSRunLoopCommonModes     默認包括上面第一和第二
UITrackingRunLoopMode 與 NSTimer

默認情況下NSTimer被加入NSDefalutRunLoopMode
如果想NSTimer受到組件或者動畫影響 添加到NSRunLoopCommonModes(OC代碼如下:)
[[NSRunLoop currentRunLoop]addTimer:timer...forMode:NSRunLoopCommonModes];
swift版代碼:

NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
RunLoopMode切換

NSDefaultRunLoopMode->UITrackingRunLoopMode->NSDefalutRunLoopMode
RunLoop的掛起與喚醒

制定用於喚醒的mach_port端口
調用mach_msg監聽喚醒端口,被喚醒前,系統內核將這個線程掛起,停留在mach_msg_trap
由另外一個線程(或另一個進程中的某個線程)向內核發送這個端口的msg後,trap狀態被喚醒,RunLoop繼續開始干活
AFNetWorking 中創建RunLoop

創建一個常駐服務線程的很好方法
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活著
[runLoop run];
swift版代碼

var loop = NSRunLoop.currentRunLoop()
loop.addPort(NSMachPort(), forMode: NSDefaultRunLoopMode)
loop.run()
一個TableView延遲加載圖片的新思路

[self.avatarImageView performSelector:@selector(serImage:)
withObjetc:downloadedImage
afterDelay:0
inModes:@[NSDefaultRunLoopMode]]
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread =
[[NSThread alloc] initWithTarget:self
selector:@selector(networkRequestThreadEntryPoint:)
object:nil];
[_networkRequestThread start];
});

return _networkRequestThread;
}
這個代碼無法轉換成swift,可能是我沒想到辦法,大家誰找到了請評論,謝謝了。

讓Crash的App回光返照 只針對Signal Crash

CFRunLoopRef runloop = CFRunLoopGetCurrent();
NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));
while(1){
for (NSString *mode in allModes){
CFRunLoopInMode((CFStringRef)mode,0.001,false);
}
}
RunLoop事件隊列
每次運行run loop,你線程的run loop對會自動處理之前未處理的消息,並通知相關的觀察者。具體的順序如下:

通知觀察者run loop已經啟動
通知觀察者任何即將要開始的定時器
通知觀察者任何即將啟動的非基於端口的源
啟動任何准備好的非基於端口的源
如果基於端口的源准備好並處於等待狀態,立即啟動;並進入步驟9。
通知觀察者線程進入休眠
將線程置於休眠直到任一下面的事件發生:
某一事件到達基於端口的源
定時器啟動
Run loop設置的時間已經超時
run loop被顯式喚醒
通知觀察者線程將被喚醒。
處理未處理的事件
如果用戶定義的定時器啟動,處理定時器事件並重啟run loop。進入步驟2
如果輸入源啟動,傳遞相應的消息
如果run loop被顯式喚醒而且時間還沒超時,重啟run loop。進入步驟2
通知觀察者run loop結束。
異步測試

- (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout{
__block Boolean fulfilled = NO;
void (^beforeWaiting) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) =
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
fulfilled = block();
if (fulfilled) {
CFRunLoopStop(CFRunLoopGetCurrent());
}
};

CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, beforeWaiting);
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

// Run!
CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);

CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
CFRelease(observer);

return fulfilled;
}

總結一下

基本上對於RunLoop,我只能說我只有簡單的模糊印象,但是不理解,也不太清楚在現實如何使用,因為實踐才能知道如何做,真的在腦裡形成了樹突,希望在未來搞定,研究透徹。看這些代碼時候我發現我的基礎知識還需要鞏固。感謝不相識的孫源。
聲明一點:不要只去收藏,去看看代碼有沒有問題,知識有沒有解釋錯誤的,交流學的更快。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved