如何理解主线程与主Runloop
这篇文章主要讲解了“如何理解主线程与主Runloop”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解主线程与主Runloop”吧!
专注于为中小企业提供成都网站制作、网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业华宁免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上1000家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
Pre
macOS:Catalina 10.15.7
Xcode:12.3
objc4:objc4-787.1
基本概念
CFRunloop
CFRunLoop
对象监视任务的输入源,并在它们准备好进行处理时分派控制。运行循环可以监视三种类型的对象:
CFRunLoopSource
、CFRunLoopTimer
和CFRunLoopObserver
。添加到运行循环中的每个源、计时器和观察者必须与一个或多个运行循环模式相关联。
Core Foundation
定义了一种特殊的伪模式,称为common modes
,它允许您将多个模式与给定的source、timer或observer关联起来。每个线程只有一个运行循环。你既不创建也不销毁线程的运行循环。
Core Foundation
会根据需要自动为您创建它。运行循环可以递归地运行。您可以在任何运行循环调用中调用
CFRunLoopRun
或CFRunLoopRunInMode
,并在当前线程的调用堆栈上创建嵌套的运行循环激活。Cocoa
应用程序构建在CFRunLoop
之上,实现它们自己的高级事件循环。在编写应用程序时,可以将源代码、计时器和观察者添加到它们的运行循环对象和模式中。然后,您的对象将作为常规应用程序事件循环的一部分被监视。使用NSRunLoop
的gettcfrunloop方法可以得到对应的CFRunLoopRef
类型。
NSRunloop
NSRunLoop
是对Core Fundation
中的CFRunloop
的封装NSRunLoop
对象处理来自窗口系统的鼠标和键盘事件、NSPort
对象和NSConnection
对象等源的输入。NSRunLoop
对象也会处理NSTimer事件。你的应用程序既不创建也不显式管理
NSRunLoop
对象。每个NSThread
对象(包括应用程序的主线程)都有一个根据需要自动创建的NSRunLoop
对象。如果需要访问当前线程的运行循环,可以使用类方法currentRunLoop
来实现。注意,从
NSRunLoop
的角度来看,NSTimer
对象不是“输入”——它们是一种特殊的类型,这意味着当它们触发时,不会导致运行循环返回。NSRunLoop
类通常被认为是线程不安全的,它的方法应该只在当前线程的上下文中被调用。永远不要尝试调用运行在不同线程中的NSRunLoop
对象的方法,因为这样做可能会导致意想不到的结果。
线程 & Runloop
先看结论!划重点!
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 ={type = mutable set, count = 2, entries => 0 : {contents = "UITrackingRunLoopMode"} 2 : {contents = "kCFRunLoopDefaultMode"} }
感谢各位的阅读,以上就是“如何理解主线程与主Runloop”的内容了,经过本文的学习后,相信大家对如何理解主线程与主Runloop这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
网站标题:如何理解主线程与主Runloop
URL地址:http://scyanting.com/article/gpejgp.html