<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
RunLoop:又叫執行迴圈機制,在iOS中的兩大機制之一。並不是只有iOS有Runloop其他語言也有,他們的方式不太一樣,但是核心都是為了解決效能和良好的執行,例如:webJs裡Runloop也稱作eventLoop,由於js沒有多執行緒,在這樣的情況做了一種呼叫棧來配合主執行緒執行。而在iOS裡面runloop就不太一樣,因為有多執行緒的原因,runloop是配合多執行緒使用的。每一個執行緒都對應一個runloop。
Runloop最核心的事情就是保證程式的持續執行讓執行緒在沒有訊息的時候休眠,在有訊息時喚醒,以提高程式效能。這個機制是依靠系統核心來完成的(蘋果作業系統核心元件 Darwin 中的 Mach)
概念:RunLoop 是通過內部維護的事件迴圈(Event Loop)來對事件/訊息進行管理的一個物件。
1、沒有訊息處理時,休眠已避免資源佔用,由使用者態切換到核心態(CPU-核心態和使用者態)
2、有訊息需要處理時,立刻被喚醒,由核心態切換到使用者態
main函數是不會退出的,為什麼呢?這個時候就是 UIApplicationMain 內部預設開啟了主執行緒的 RunLoop,並執行了一段無限迴圈的程式碼(不是簡單的 for 循 環或 while 迴圈)
int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
UIApplicationMain 函數一直沒有返回,而是不斷地接收處理訊息以及等待休眠,所以執行程式之後會保 持持續執行狀態
// 虛擬碼 int main(int argc, char * argv[]) { BOOL running = YES; do { //執行的事件 } while(running) return 0; }
RunLoop 通過 mach_msg()函數接收、傳送訊息。它的本質是呼叫函數 mach_msg_trap(),相當於是一 個系統呼叫,會觸發核心狀態切換。
在使用者態呼叫 時會切換到核心態;核心態中核心 實現的 mach_msg()函數會完成實際的工作。
是 CFRunLoop(CoreFoundation)的封裝,提供了物件導向的 API 相關的主要涉及五個類:
CFRunLoopSource分為兩種source0和source1詳解:
CFRunLoopObserver監聽時間點詳細事件
執行緒和 RunLoop 一一對應, RunLoop 和 Mode 是一對多的,Mode 和 source、timer、observer 也是一對多 的
Runloop執行的大致邏輯是:
通知觀察者 RunLoop 即將啟動。
通知觀察者即將要處理 Timer 事件。
通知觀察者即將要處理 source0 事件。
處理 source0 事件。
如果基於埠的源(Source1)準備好並處於等待狀態,進入步驟 9。
通知觀察者執行緒即將進入休眠狀態。
將執行緒置於休眠狀態,由使用者態切換到核心態,直到下面的任一事件發生才喚醒執行緒。
通知觀察者執行緒將被喚醒。
處理喚醒時收到的事件
通知觀察者 RunLoop 結束。
觀察者observer 怎麼監聽Runloop,監聽的狀態
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { // 即將進入runloop kCFRunLoopEntry = (1UL << 0), // 即將處理timer kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理source kCFRunLoopBeforeSources = (1UL << 2), // 即將進入休眠 kCFRunLoopBeforeWaiting = (1UL << 5), // 休眠後喚醒 kCFRunLoopAfterWaiting = (1UL << 6), // 退出runloop kCFRunLoopExit = (1UL << 7), // runloop所有活動 kCFRunLoopAllActivities = 0x0FFFFFFFU };
1、怎麼建立一個常駐執行緒?
NSRunLoop *runloop = [NSRunLoop currentRunLoop]; [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runloop run];
2、如果我們開闢一個新的執行緒 加入了定時器的 這個時候定時器是不會執行的,我們看下下面的程式碼
- (void)viewDidLoad { [super viewDidLoad]; NSLogMeth(@"1") ygweakify(self); dispatch_async(dispatch_get_global_queue(0, 0), ^{ ygstrongify(self); NSLogMeth(@"2") [self performSelector: @selector(test) afterDelay:10]; NSLogMeth(@"3") }); NSLogMeth(@"4") } - (void)test { NSLogMeth(@"5") }
答案是 1423,test 方法並不會執行。
原因是如果是帶 afterDelay 的延時函數,會在內部建立一個 NSTimer,然後新增到當前執行緒的 RunLoop 中。 也就是如果當前執行緒沒有開啟 RunLoop,該方法會失效。
我們再看另一個
dispatch_async(dispatch_get_global_queue(0, 0), ^{ ygstrongify(self); NSLogMeth(@"2") [NSRunLoop currentRunLoop] run]; [self performSelector: @selector(test) afterDelay:10]; NSLogMeth(@"3") }); NSLogMeth(@"4") }
答案依然是 1423,test 方法並不會執行。
原因是如果 RunLoop 的 mode 中一個 item 都沒有,RunLoop 會退出。即在呼叫 RunLoop 的 run 方法後,由 於其 mode 中沒有新增任何 item 去維持 RunLoop 的時間迴圈,RunLoop 隨即還是會退出。 所以我們自己啟動 RunLoop,一定要在新增 item 後 所以我們把 開啟runloop的程式碼 放在 延時方法之後 就好了
dispatch_async(dispatch_get_global_queue(0, 0), ^{ ygstrongify(self); NSLogMeth(@"2") [self performSelector: @selector(test) afterDelay:10]; [NSRunLoop currentRunLoop] run]; NSLogMeth(@"3") }); NSLogMeth(@"4") }
這個時候test的方法就執行了
3、怎樣保證子執行緒資料回來更新 UI 的時候不打斷使用者的滑動操作?
當我們在子請求資料的同時滑動瀏覽當前頁面,如果資料請求成功要切回主執行緒更新 UI,那麼就會影響當 前正在滑動的體驗。
我們就可以將更新 UI 事件放在主執行緒的 上執行即可,這樣就會等使用者不再滑動頁 面,主執行緒 RunLoop 由 切換到 時再去更新 UI
[self performSelectorOnMainThread: @selector(readload) withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];
4、NSTimer 在runloop中的關係
NSTimer其實就是 CFRunLoopTimerRef(基於時間的觸發器) ,他們之間是tool-free bridged 的。一個 NSTimer 註冊到RunLoop後, RunLoop會為其重複的時間點註冊好事件。例如 10:00, 10:10, 10:20 這幾個時間點。 RunLoop為了節省資源,並不會在非常準確的時間點回撥這個 Timer。Timer 有個屬性叫做Tolerance(寬容度),標示了當時間點到後,容許有多少最大誤差。
如果某個時間點被錯過了,例如執行了一個很長的任務,則那個時間點的回撥也會跳過去,不會延後執行。就比如等公交,如果 10:10 時我忙著玩手機錯過了那個點的公交,那我只能等 10:20 這一趟了。
CADisplayLink 是一個和螢幕重新整理率一致的定時器(但實際實現原理更復雜,和 NSTimer 並不一樣, 其內部實際是操作了一個 Source)。如果在兩次螢幕重新整理之間執行了一個長任務,那其中就會有一幀被 跳過去(和NSTimer相似),造成介面卡頓的感覺。在快速滑動 TableView 時,即使一幀的卡頓也會 讓使用者有所察覺。 FaceBook開源的 AsyncDisplayLink 就是為了解決介面卡頓的問題,其內部也用 到了 RunLoop
非同步繪製,就是可以在子執行緒把需要繪製的圖形,提前在子執行緒處理好。將準備好影象資料直接返給主執行緒使用,這樣可以降低主執行緒的壓力。(一般情況下我們都是在主執行緒繪製的大家可以作為了解,特殊情況下在處理研究)
非同步繪製的過程:
要通過系統的 [view.delegate displayLayer:] 這個入口來實現非同步繪製。
以上就是iOS開發runloop執行迴圈機制學習的詳細內容,更多關於iOS runloop執行迴圈的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45