我读了这个apple doc about runloop:
运行循环是一个事件处理循环,用于调度工作并协调传入事件的接收...运行循环从两种不同类型的源接收事件。输入源提供异步事件...定时器源提供同步事件......
现在我知道performSelector:withObject:afterDelay:
和NSTimer
在runloop中运行。
doc没有提到触摸事件作为输入源。我想知道:
Q1:[UIApplication sendEvent:]
发送的触摸事件是否也会在某个默认的runloop中运行?
Q2:如果Q1的答案为YES,那么默认的runloop是同一个runloop处理performSelector:withObject:afterDelay:
和NSTimer
个事件吗?
答案 0 :(得分:10)
我不会假装答案准确无误只是我的猜测。
我将在这个答案中介绍:
我并不熟悉马赫,(我计划将来更深入地学习马赫)但我知道马赫内核运作的基本原语。 Mach内核使用端口通过发送消息在进程之间进行通信。您可以将流程视为您的应用程序。
Project purple 是iOS的简单代号。我为什么提这个?因为有一个马赫'紫色系统事件'用于发送 SpringBoard 应用程序的系统事件的端口。
据我所知,有私人 GraphicsServices框架 ,其中包含:
GraphicServices框架使用mach'紫色系统事件'发送所有事件。端口。
如果您有兴趣,可以在此处查看其标题:
https://github.com/rpetrich/iphoneheaders/tree/master/GraphicsServices
iOS有一个名为SpringBoard的应用程序,用户在iPhone / iPad / iPod上导航时会看到它,它负责启动应用程序,向它们发送接收来自它们的通知的事件等等。我认为你已经猜到SpringBoard从Purple系统事件端口接收事件,并且几乎所有事件都被传递给活动应用程序。 (有些事件只与SpringBoard有关,例如设备锁定。)
有关SpringBoard的更多信息,请查看:
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时,它只是等待来自端口的消息。
在给定的屏幕截图中,您可以看到UIApplicationMain
函数调用GraphicServices框架无限循环,以便通过调用mach_msg
进入模块并等待事件进入陷阱:mach_msg_trap
。它使线程进入睡眠状态,并在新事件到来时唤醒。另外 UIKit ,因为我看到为 SpringBoard 提供的事件注册了自己的回调。稍后我们将在事件到达的堆栈跟踪PurpleEventCallback
和_PurpleEventCallback
函数调用中看到。这个函数充当所有GraphicServices和UIKit之间的桥梁。 (我的意思是我们在UIEvent中收到由UIKit包装的GSEvent等)你可以看到函数名是“紫色项目”的复活节彩蛋。代号。
至于 UIKit 我假设它注册了自己的CFRunloopSourceRef
,它调用_UIApplicationHandleEventQueue
函数并处理触摸和其他内容。 (将它们委托给您的应用程序)查看屏幕截图(系统如何处理触摸):
当应用程序暂停时, UIKit 会使此来源无效。看截图。 (我在CFRunLoopRemoveSource
上设置了符号断点,你可以在堆栈跟踪中看到UIKit准备挂起应用程序。)然后我选择CFRunLoopSourceInvalidate
帧来查明这个运行循环源是否与马赫的东西。 CFRunLoopSourceInvalidate
方法有以下原型:
void CFRunLoopSourceInvalidate (
CFRunLoopSourceRef source
);
因此,使用lldb并且知道参数应该存储在方法调用的寄存器中,我打印出寄存器值并读取与mach内容相关的建议参数。如你所见 - 这是真的。
UIKit 也会通知成功发布,成功暂停等通知?的 跳板 即可。有一种特定的方法用于发送名为GSSendEvent()
的特定机器端口的事件。通过那里的端口是应用程序的事件端口。有关更多信息,请查看:
http://iphonedevwiki.net/index.php/GSEvent
还有一些截图展示了这种沟通:
应用程序完成了启动并将其报告回 SpringBoard :
应用程序收到事件,您可以看到它正在做一些内部事务,设置状态栏,从故事板实例化视图控制器,报告回来等等:
暂停应用程序调用堆栈:
<强>要点:强>
GraphicServices 使用&#39;紫色系统事件&#39;用于发送与触摸,设备锁定,挂起活动应用程序等相关的事件的端口 SpringBoard 接收来自&#39;紫色系统事件&#39;端口并通过获取其事件端口将它们发送到活动应用程序。 UIKit 接收它们,处理它们,并可能使用 SpringBoard将结果发送回 SpringBoard 事件端口。
答案 1 :(得分:1)
不一定。 performSelector:withObject:afterDelay:
和NSTimer
将在调用事件的线程的runloop上运行,而sendEvent:
应该在主runloop上运行。