2014-03-01 21 views
1

我讀這apple doc about runloop[UIApplication sendEvent:]是否在NSRunLoop中執行?

一個運行循環是指用於安排工作,並協調接收傳入事件的...一個運行循環接收來自兩個不同類型的源事件的事件處理循環。輸入源傳遞異步事件......定時器源提供的同步事件...

現在我知道performSelector:withObject:afterDelay:並在runloop NSTimer運行。

該文檔沒有提及觸摸事件作爲輸入源。我在想:

Q1:不要觸摸事件由[UIApplication sendEvent:]運行中一些默認runloop發送嗎?
Q2:如果Q1的答案是肯定的,就是默認runloop相同runloop處理performSelector:withObject:afterDelay:NSTimer事件?

回答

9

我不會假裝我的答案的準確性只是我的猜測。

我會在這個答案包括:

  1. 馬赫IPC/RPC。 (進程間通信/遠程過程調用)
  2. 項目紫色。 (iOS代號)
  3. GraphicsServices。 (Private Framework)
  4. SpringBoard。 (iOS的GUI應用程序)
  5. Runloop本身。 (它的作用,在這一切的)

我不是很熟悉馬赫,(我打算更深入地瞭解它在未來的),但我知道基本的原語的馬赫內核的運行。馬赫內核通過發送消息用來過程之間的通信端口。您可以將流程視爲您的應用程序。


項目紫是爲iOS簡單的代號。爲什麼我提到這個?因爲有一個馬赫「紫系統事件」,其被用來發送系統事件爲跳板應用端口。


據我所知有私人GraphicsServices框架其中有:

  • 檢查設備功能。 (相機,藍牙,GPS等)
  • 獲取屏幕大小/尺寸,取向
  • :呈現/隱藏/管理鍵盤
  • 當然而發送事件觸摸,音量設置,無聲振鈴開關,設備鎖定等)

GraphicServices框架使用mach'紫色系統事件'端口發送所有事件。

在這裏,你可以看一下它的頭,如果你有興趣:

https://github.com/rpetrich/iphoneheaders/tree/master/GraphicsServices


的iOS有應用程序調用跳板這就是用戶看到他用iPhone/iPad/iPod和航行時它負責啓動應用程序,向他們發送接收通知的事件等等。我認爲你已經猜到SpringBoard從Purple系統事件端口接收事件,並且幾乎所有事件都被傳遞到活動應用程序。 (有一些,只有相關的跳板,如設備鎖定的事件。)

更多有關跳板看看有:

http://theiphonewiki.com/wiki//System/Library/CoreServices/SpringBoard.app


現在什麼的作用runloop在所有這一切?如果您查看CFRunloopRef的源代碼,您可以看到它與mach端口緊密配合。 (源代碼可在:https://www.opensource.apple.com/source/CF/CF-476.10/CFRunLoop.c

當您調用CFRunLoopRun時,它只是等待來自端口的消息。

Application waits for messages from mach kernel

在給定的截圖可以看到,UIApplicationMain函數調用GraphicServices框架無限循環的模態運行,並通過調用mach_msg在陷阱進入等待事件:​​。它使線程進入睡眠狀態,並在新事件到來時喚醒線程。 UIKit因爲我看到註冊自己的回調事件SpringBoard交付。我們將在後面的堆棧跟蹤PurpleEventCallback_PurpleEventCallback函數調用事件到達。這個函數充當所有GraphicServices和UIKit之間的橋樑。 (我的意思是我們收到UIEvent中UIKit包裝的GSEvent等)。您可以看到函數名稱是'Project Purple'代號的復活節彩蛋。

至於的UIKit我認爲它註冊自己CFRunloopSourceRef調用_UIApplicationHandleEventQueue功能和處理這樣的東西,觸摸等。(其中委託給你的應用程序),見截圖(如何通過觸摸系統處理):

Touching screen stack trace

當應用程序暫停 - 的UIKit無效此源。看截圖。 (我已經在CFRunLoopRemoveSource上設置了符號斷點,正如你可以在堆棧跟蹤中看到的那樣,UIKit準備掛起應用程序。)然後,我選擇CFRunLoopSourceInvalidate框架來確定此運行循環源是否與mach相關。該CFRunLoopSourceInvalidate方法具有以下原型:

void CFRunLoopSourceInvalidate ( CFRunLoopSourceRef source );

因此,使用LLDB和具有知識的參數應該存儲在方法調用一個寄存器我打印出來寄存器值和讀取建議參數馬赫的東西有關。正如你所看到的 - 這是真的。

Invalidating runloop source


的UIKit還通知有關成功發射,成功的懸浮等爲誰它通知? SpringBoard。有一種特定的方法用於發送特定的馬達端口事件GSSendEvent()。通過的端口是應用程序的事件端口。欲瞭解更多信息,請看:

http://iphonedevwiki.net/index.php/GSEvent

也有一些截圖,展示此通信:

應用完成了它的啓動和報告這一回跳板

Application finished launching

應用程序收到的事件,你可以看到它正在做一些內部的東西,設定狀態欄,從故事板實例視圖控制器,回報等:

Some events handled by UIKit

掛起應用調用堆棧:

Suspending application

總結:

GraphicServices種用途「紫系統事件」端口發送與觸摸,設備鎖定事件,懸浮劑活性施用等 跳板從「紫系統事件」端口接收消息,並通過獲取其事件端口它們發送到活動的應用程序。UIKit的接收它們,處理它們,並且可以發送使用跳板事件端口結果回到跳板


+0

不錯的工作!調用堆棧顯示我應該在runloop中發生'sendEvent:'。 :) – smilingpoplar

+0

現在我還有一個問題:runloop是否和runloop一樣處理'performSelector:withObject:afterDelay:'和'NSTimer'事件? – smilingpoplar

+1

Runloop只處理** UIKit **爲從** SpringBoard **獲取事件而設置的源(例如觸及)。 您自動擁有**一個**每個線程的runloop。所以是的,這是處理你的觸摸相同的runloop。 * performSelector:withObject:afterDelay:*和* NSTimer:*是某種* CFRunLoopTimerRef *。如果您進一步閱讀了關於CFRunloopRef的信息,您可以看到它在3件事情上運行 - 來源,**定時器**,觀察者。 當你調用上面的方法時:在幕後它只是將* CFRunLoopTimerRef *廣告給當前的runloop。 –

1

不一定。 performSelector:withObject:afterDelay:NSTimer將在調用它們的線程的runloop上運行,而sendEvent:應該在主runloop上運行。