您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何理解主線程與主Runloop”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何理解主線程與主Runloop”吧!
macOS:Catalina 10.15.7
Xcode:12.3
objc4:objc4-787.1
CFRunLoop
對象監視任務的輸入源,并在它們準備好進行處理時分派控制。
運行循環可以監視三種類型的對象:CFRunLoopSource
、CFRunLoopTimer
和CFRunLoopObserver
。
添加到運行循環中的每個源、計時器和觀察者必須與一個或多個運行循環模式相關聯。
Core Foundation
定義了一種特殊的偽模式,稱為common modes
,它允許您將多個模式與給定的source、timer或observer關聯起來。
每個線程只有一個運行循環。你既不創建也不銷毀線程的運行循環。Core Foundation
會根據需要自動為您創建它。
運行循環可以遞歸地運行。您可以在任何運行循環調用中調用CFRunLoopRun
或CFRunLoopRunInMode
,并在當前線程的調用堆棧上創建嵌套的運行循環激活。
Cocoa
應用程序構建在CFRunLoop
之上,實現它們自己的高級事件循環。在編寫應用程序時,可以將源代碼、計時器和觀察者添加到它們的運行循環對象和模式中。然后,您的對象將作為常規應用程序事件循環的一部分被監視。使用NSRunLoop
的gettcfrunloop方法可以得到對應的CFRunLoopRef
類型。
NSRunLoop
是對Core Fundation
中的CFRunloop
的封裝
NSRunLoop
對象處理來自窗口系統的鼠標和鍵盤事件、NSPort
對象和NSConnection
對象等源的輸入。NSRunLoop
對象也會處理NSTimer事件。
你的應用程序既不創建也不顯式管理NSRunLoop
對象。每個NSThread
對象(包括應用程序的主線程)都有一個根據需要自動創建的NSRunLoop
對象。如果需要訪問當前線程的運行循環,可以使用類方法currentRunLoop
來實現。
注意,從NSRunLoop
的角度來看,NSTimer
對象不是“輸入”——它們是一種特殊的類型,這意味著當它們觸發時,不會導致運行循環返回。
NSRunLoop
類通常被認為是線程不安全的,它的方法應該只在當前線程的上下文中被調用。永遠不要嘗試調用運行在不同線程中的NSRunLoop
對象的方法,因為這樣做可能會導致意想不到的結果。
Cocoa和Core Foundation都提供了運行循環對象(NSRunloop
和CFRunloop
)來幫助配置和管理線程的運行循環。
應用程序不需要顯式地創建這些對象;每個線程(包括主線程)都有一個關聯的Runloop對象。
作為應用程序啟動過程的一部分,應用程序框架自動在主線程上設置并運行運行循環。而子線程需要顯式地運行它們的運行循環。
關系概括:App啟動后,蘋果在主線程創建了其關聯的Runloop,并在該Runloop
中注冊兩個Observer
第一個事件:BeforeWaiting(準備進入休眠),回調內會調用_objc_autoreleasePoolPop()
釋放舊的池并調用_objc_autoreleasePoolPush()
創建新的池
第二個事件:Exit(即將退出Loop
),回調內會調用_objc_autoreleasePoolPop()
銷毀自動釋放池
第一個Observer
(優先級最高)監控的事件:Entry(即將進入Loop
),回調內會調用_objc_autoreleasePoolPush()
創建自動釋放池
第二個Observer
(優先級最低)監控兩個事件:
根據調用堆棧我們可以看出來,當調用UIApplicationMain()
方法后,系統會自動為其創建相關聯的Runloop
。
通過在main()函數首行即獲取主線程與主runloop可以看到:此時主線程的runloop已經存在了。我們可以推測出主線程創建后即會創建對應的runloop,也就是說,主runloop在程序一啟動就默認創建好了。 但是此時的主runloop中,還未添加相關觀察者等等。
當代碼從main()開始執行,此時的runloop依然是一個空的結構體
查看進入applicationDidLaunchingWithOptions:
之前的調用堆棧 可以看到會為此時的主Runloop添加Source等相關信息
走進applicationDidLaunchingWithOptions
時,再通過po CFRunloopGetMain()
獲取此時的主Runloop信息,可以看到觀察者、source等都已添加完成
// 截取部分 current mode = kCFRunLoopDefaultMode, common modes = <CFBasicHash 0x6000014e5260 [0x7fff8002e8c0]>{type = mutable set, count = 2, entries => 0 : <CFString 0x7fff806610e0 [0x7fff8002e8c0]>{contents = "UITrackingRunLoopMode"} 2 : <CFString 0x7fff801ab7e8 [0x7fff8002e8c0]>{contents = "kCFRunLoopDefaultMode"} }
感謝各位的閱讀,以上就是“如何理解主線程與主Runloop”的內容了,經過本文的學習后,相信大家對如何理解主線程與主Runloop這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。