色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

您好,歡迎來電子發燒友網! ,新用戶?[免費注冊]

您的位置:電子發燒友網>源碼下載>通訊/手機編程>

關于iOS的事件處理機制解析

大小:0.3 MB 人氣: 2017-09-26 需要積分:1

  RunLoop主要處理以下6類事件:

  static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(); static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(); static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__();

  Observer事件,runloop中狀態變化時進行通知。(微信卡頓監控就是利用這個事件通知來記錄下最近一次main runloop活動時間,在另一個check線程中用定時器檢測當前時間距離最后一次活動時間過久來判斷在主線程中的處理邏輯耗時和卡主線程)。這里還需要特別注意,CAAnimation是由RunloopObserver觸發回調來重繪,接下來會講到。

  Block事件,非延遲的NSObject PerformSelector立即調用,dispatch_after立即調用,block回調。

  Main_Dispatch_Queue事件:GCD中dispatch到main queue的block會被dispatch到main loop執行。

  Timer事件:延遲的NSObject PerformSelector,延遲的dispatch_after,timer事件。

  Source0事件:處理如UIEvent,CFSocket這類事件。需要手動觸發。觸摸事件其實是Source1接收系統事件后在回調 __IOHIDEventSystemClientQueueCallback() 內觸發的 Source0,Source0 再觸發的 _UIApplicationHandleEventQueue()。source0一定是要喚醒runloop及時響應并執行的,如果runloop此時在休眠等待系統的 mach_msg事件,那么就會通過source1來喚醒runloop執行。

  Source1事件:處理系統內核的mach_msg事件。(推測CADisplayLink也是這里觸發)。

  RunLoop執行順序的偽代碼

  SetupThisRunLoopRunTimeoutTimer(); // by GCD timer //通知即將進入runloop__CFRUNLLOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(KCFRunLoopEntry); do { __CFRunLoopDoObservers(kCFRunLoopBeforeTimers); __CFRunLoopDoObservers(kCFRunLoopBeforeSources); __CFRunLoopDoBlocks(); //一個循環中會調用兩次,確保非延遲的NSObject PerformSelector調用和非延遲的dispatch_after調用在當前runloop執行。還有回調block __CFRunLoopDoSource0(); //例如UIKit處理的UIEvent事件 CheckIfExistMessagesInMainDispatchQueue(); //GCD dispatch main queue __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting); //即將進入休眠,會重繪一次界面 var wakeUpPort = SleepAndWaitForWakingUpPorts(); // mach_msg_trap,陷入內核等待匹配的內核mach_msg事件 // Zzz.。。 // Received mach_msg, wake up __CFRunLoopDoObservers(kCFRunLoopAfterWaiting); // Handle msgs if (wakeUpPort == timerPort) { __CFRunLoopDoTimers(); } else if (wakeUpPort == mainDispatchQueuePort) { //GCD當調用dispatch_async(dispatch_get_main_queue(),block)時,libDispatch會向主線程的runloop發送mach_msg消息喚醒runloop,并在這里執行。這里僅限于執行dispatch到主線程的任務,dispatch到其他線程的仍然是libDispatch來處理。 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() } else { __CFRunLoopDoSource1(); //CADisplayLink是source1的mach_msg觸發? } __CFRunLoopDoBlocks(); } while (!stop && !timeout); //通知observers,即將退出runloop __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBERVER_CALLBACK_FUNCTION__(CFRunLoopExit);

  結合上面的Runloop事件執行順序,思考下面代碼邏輯中為什么可以標識tableview是否reload完成

  dispatch_async(dispatch_get_main_queue(), ^{ _isReloadDone = NO; [tableView reload]; //會自動設置tableView layoutIfNeeded為YES,意味著將會在runloop結束時重繪table dispatch_async(dispatch_get_main_queue(),^{ _isReloadDone = YES; }); });

  提示:這里在GCD dispatch main queue中插入了兩個任務,一次RunLoop有兩個機會執行GCD dispatch main queue中的任務,分別在休眠前和被喚醒后。

  iOS 為什么必須在主線程中操作UI

  因為UIKit不是線程安全的。試想下面這幾種情況:

  兩個線程同時設置同一個背景圖片,那么很有可能因為當前圖片被釋放了兩次而導致應用崩潰。

  兩個線程同時設置同一個UIView的背景顏色,那么很有可能渲染顯示的是顏色A,而此時在UIView邏輯樹上的背景顏色屬性為B。

  兩個線程同時操作view的樹形結構:在線程A中for循環遍歷并操作當前View的所有subView,然后此時線程B中將某個subView直接刪除,這就導致了錯亂還可能導致應用崩潰。

  iOS4之后蘋果將大部分繪圖的方法和諸如 UIColor 和 UIFont 這樣的類改寫為了線程安全可用,但是仍然強烈建議講UI操作保證在主線程中執行。

  事件響應

  蘋果注冊了一個 Source1 (基于 mach port 的) 用來接收系統事件,其回調函數為 __IOHIDEventSystemClientQueueCallback()。

  當一個硬件事件(觸摸/鎖屏/搖晃等)發生后,首先由 IOKit.framework 生成一個 IOHIDEvent 事件并由 SpringBoard 接收。

  SpringBoard 只接收按鍵(鎖屏/靜音等),觸摸,加速,接近傳感器等幾種 Event,隨后用 mach port 轉發給需要的App進程。隨后蘋果注冊的那個 Source1 就會觸發回調,并調用 _UIApplicationHandleEventQueue() 進行應用內部的分發。

  _UIApplicationHandleEventQueue() 會把 IOHIDEvent 處理并包裝成 UIEvent 進行處理或分發,其中包括識別 UIGesture/處理屏幕旋轉/發送給 UIWindow 等。通常事件比如 UIButton 點擊、touchesBegin/Move/End/Cancel 事件都是在這個回調中完成的。

  CALayer

  在iOS當中,所有的視圖都從一個叫做UIVIew的基類派生而來,UIView可以處理觸摸事件,可以支持基于Core Graphics繪圖,可以做仿射變換(例如旋轉或者縮放),或者簡單的類似于滑動或者漸變的動畫。

  CALayer類在概念上和UIView類似,同樣也是一些被層級關系樹管理的矩形塊,同樣也可以包含一些內容(像圖片,文本或者背景色),管理子圖層的位置。它們有一些方法和屬性用來做動畫和變換。和UIView最大的不同是CALayer不處理用戶的交互。CALayer并不清楚具體的響應鏈。

  UIView和CALayer是一個平行的層級關系,每一個UIView都有一個CALayer實例的圖層屬性,也就是所謂的backing layer,視圖的職責就是創建并管理這個圖層,以確保當子視圖在層級關系中添加或者被移除的時候,他們關聯的圖層也同樣對應在層級關系樹當中有相同的操作。實際上這些背后關聯的Layer圖層才是真正用來在屏幕上顯示和做動畫,UIView僅僅是對它的一個封裝,提供了一些iOS類似于處理觸摸的具體功能,以及Core Animation底層方法的高級接口。

  UIView 的 Layer 在系統內部,被維護著三份同樣的樹形數據結構,分別是:

  圖層樹(這里是代碼可以操縱的,設置屬性的最終值會立刻在這里更新);

  呈現樹(是一個中間層,系統就在這一層上更改屬性,進行各種渲染操作。比如一個動畫是更改alpha值從0到1,那么在邏輯樹上此屬性會被立刻更新為最終屬性1,而在動畫樹上會根據設置的動畫時間從0逐步變化到1);

  渲染樹(其屬性值就是當前正被顯示在屏幕上的屬性值);

  CADisplayLink 和 NSTimer

  NSTimer 其實就是 CFRunLoopTimerRef。一個 NSTimer 注冊到 RunLoop 后,RunLoop 會為其重復的時間點注冊好事件。

  RunLoop為了節省資源,并不會在非常準確的時間點回調這個Timer。Timer 有個屬性叫做 Tolerance (寬容度),標示了當時間點到后,容許有多少最大誤差。如果某個時間點被錯過了,例如執行了一個很長的任務,則那個時間點的回調也會跳過去,不會延后執行。

  RunLoop 是用GCD的 dispatch_source_t 實現的 Timer。 當調用 NSObject 的 performSelecter:afterDelay: 后,實際上其內部會創建一個 Timer 并添加到當前線程的 RunLoop 中。所以如果當前線程沒有 RunLoop,則這個方法會失效。當調用 performSelector:onThread: 時,實際上其會創建一個 Timer 加到對應的線程去,同樣的,如果對應線程沒有 RunLoop 該方法也會失效。

  CADisplayLink 是一個和屏幕刷新率(每秒刷新60次)一致的定時器(但實際實現原理更復雜,和 NSTimer 并不一樣,其內部實際是操作了一個 Source)。如果在兩次屏幕刷新之間執行了一個長任務,那其中就會有一幀被跳過去,造成界面卡頓的感覺。

  iOS 渲染過程

  關于iOS的事件處理機制解析

  圖2-1

  通常來說,計算機系統中 CPU、GPU、顯示器是以上面這種方式協同工作的。CPU 計算好顯示內容提交到 GPU,GPU 渲染完成后將渲染結果放入幀緩沖區,隨后視頻控制器會按照 VSync 信號如下圖1-4所示,逐行讀取幀緩沖區的數據,經過可能的數模轉換傳遞給顯示器顯示。

  關于iOS的事件處理機制解析

  圖2-2

  在 VSync 信號到來后,系統圖形服務會通過 CADisplayLink 等機制通知 App,App 主線程開始在 CPU 中計算顯示內容,比如視圖的創建、布局計算、圖片解碼、文本繪制等。隨后 CPU 會將計算好的內容提交到 GPU 去,由 GPU 進行變換、合成、渲染。隨后 GPU 會把渲染結果提交到幀緩沖區去,等待下一次 VSync 信號到來時顯示到屏幕上。由于垂直同步的機制,如果在一個 VSync 時間內,CPU 或者 GPU 沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時顯示屏會保留之前的內容不變。這就是界面卡頓的原因。從上圖中可以看到,CPU 和 GPU 不論哪個阻礙了顯示流程,都會造成掉幀現象。所以開發時,也需要分別對 CPU 和 GPU 壓力進行評估和優化。

  關于iOS的事件處理機制解析

  iOS 的顯示系統是由 VSync 信號驅動的,VSync 信號由硬件時鐘生成,每秒鐘發出 60 次(這個值取決設備硬件,比如 iPhone 真機上通常是 59.97)。iOS 圖形服務接收到 VSync 信號后,會通過 IPC 通知到 App 內。App 的 Runloop 在啟動后會注冊對應的 CFRunLoopSource 通過 mach_port 接收傳過來的時鐘信號通知,隨后 Source 的回調會驅動整個 App 的動畫與顯示。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

      發表評論

      用戶評論
      評價:好評中評差評

      發表評論,獲取積分! 請遵守相關規定!

      ?
      主站蜘蛛池模板: 日本亚洲欧洲免费旡码| 男人就爱吃这套下载| 精品国产乱码久久久人妻| 日韩做A爰片久久毛片A片毛茸茸| 中文字幕精品在线视频| 好男人WWW免费高清视频在线| 色宅男看片午夜大片免费看| gratis videos欧美最新| 邻家美姨在线观看全集免费| 伊人影院综合网| 久久无码人妻AV精品一区| 野花日本韩国视频免费高清观看 | 日本精油按摩| 成年无码av片| 肉肉的各种姿势高H细文| 成 人 片 免费播放| 日本人bbwbbwbbwbbw| 国产99青草全福视在线| 色人阁影视| 国产精品免费一区二区三区四区| 试看2分钟AA片| 国产亚洲精品99一区二区| 亚洲日本欧美国产在线视| 久草视频在线观看免费4| 影音先锋男人资源813.| 龙腾亚洲人成电影网站| 99久久婷婷国产麻豆精品电影| 欧美XXXX69学生HD| 高清国语自产拍在线| 亚洲m男在线中文字幕| 久久xxxx| H揉捏娇喘乳叫床NP调教视频| 色尼玛亚洲| 娇妻让壮男弄的流白浆| 506070老熟肥妇bbwxx视频| 秋霞电影网视频一区二区三区 | 色中色成人论坛| 国产亚洲精品久久久999蜜臀| 永久精品免费影院在线观看网站| 老师破女学生特级毛片| 啊好大好厉害好爽真骚|