Reputation: 1075
I read this apple doc about runloop:
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events... A run loop receives events from two different types of sources. Input sources deliver asynchronous events... Timer sources deliver synchronous events...
Now I know performSelector:withObject:afterDelay:
and NSTimer
run in a runloop.
The doc doesn't mention touch events as input sources. I wonder:
Q1: Do touch events sent by [UIApplication sendEvent:]
run in some default runloop too?
Q2: If Q1's answer is YES, is that default runloop the same runloop handles performSelector:withObject:afterDelay:
and NSTimer
events?
Upvotes: 3
Views: 2888
Reputation: 4145
Not necessarily. performSelector:withObject:afterDelay:
and NSTimer
will run on the runloop of the thread that called events them, whereas sendEvent:
should run on the main runloop.
Upvotes: 1
Reputation: 848
I won't pretend on accurateness of my answer its only just my guesses.
What I will cover in this answer:
I'm not really familiar with mach, (I'm planning to learn it more deeply in future) but I know basic primitives on which mach kernel operates. Mach kernel uses ports for communication between processes by sending messages. You can think of a process as your application.
Project purple is simple codename for iOS. Why I mention this? Because there is a mach 'Purple system event' port which is used to send system event for SpringBoard application.
As I know there are private GraphicsServices framework which has:
GraphicServices framework is sending all events using mach 'Purple system event' port.
Here you can look at its headers if you are interested:
https://github.com/rpetrich/iphoneheaders/tree/master/GraphicsServices
iOS have application called SpringBoard that is what user see when navigating on his iPhone/iPad/iPod and it's responsible for launching applications, sending them events receiving notifications from them and so on. And I think that you've already guessed that SpringBoard receives events from Purple system event port and almost all of them are passed to active application. (There are some events that only related for SpringBoard, for example device locking.)
For more information about SpringBoard look there:
http://theiphonewiki.com/wiki//System/Library/CoreServices/SpringBoard.app
And now what's the role of runloop in all of that? If you look at the source code for CFRunloopRef
you can see that it works tightly with mach ports. (Source code can be found at : https://www.opensource.apple.com/source/CF/CF-476.10/CFRunLoop.c)
When you call CFRunLoopRun it simply waits for messages from port(s).
On the given screenshot you can see that UIApplicationMain
function calls GraphicServices framework infinity loop for running modally and waiting for events via call mach_msg
that enters in trap : mach_msg_trap
. It puts thread into sleep and wake up when new event arrives. Also UIKit as I see registers its own callback for events that SpringBoard deliver. We will see later in stack trace PurpleEventCallback
and _PurpleEventCallback
function calls on event arriving. This functions acts as a bridge between all GraphicServices and UIKit stuff. (I mean we receive GSEvent that is wrapped by UIKit in UIEvent, etc.) You can see that function names are easter eggs for 'Project Purple' codename.
As for UIKit I assume that it register its own CFRunloopSourceRef
that invokes _UIApplicationHandleEventQueue
function and handles such stuff as touches and other. (delegates them to your application) See screenshot (How is touch handled by system):
And when application suspends - UIKit invalidates this sources. Look at screenshot. (I've set symbolic breakpoint on CFRunLoopRemoveSource
and as you can see in stack trace UIKit prepares to suspend application.) Then I choose CFRunLoopSourceInvalidate
frame to find out if this run loop source is related to mach stuff. The CFRunLoopSourceInvalidate
method has following prototype :
void CFRunLoopSourceInvalidate (
CFRunLoopSourceRef source
);
So using lldb and having knowledge that arguments should be stored in a registers on method invocation I've printed out register values and read suggested argument to be related to mach stuff. As you can see - it's true.
UIKit also notifies about successful launch, successful suspending etc. Whom it notifies? SpringBoard. There is specific method that used to send events for specific mach port called GSSendEvent()
. Port passed there is the application's event port. For more information look:
http://iphonedevwiki.net/index.php/GSEvent
Also some screenshots that demonstrate this communication:
Application finished its launching and reports this back to SpringBoard:
Application received event and you can see it's doing some internal things, setting status bar, instantiating view controller from storyboard, reporting back, etc:
Suspending application call stack:
Summary:
GraphicServices uses 'Purple system event' port to send events related to touches, device locks, suspending active application etc. SpringBoard receives messages from 'Purple system event' port and sends them to active application by getting its event port. UIKit receives them, handles them, and may sends result back to SpringBoard using SpringBoard event port.
Upvotes: 16