IOS RunLoop programming manual (translation)

This is a document on the development of Run Threading Program Guide:Run Loops, the translation, from Apple Development documents.

Run loops is the basic part of the thread. A run loop is a cycle that is used to schedule work and coordinate the accepted events. The purpose of a run loop is to keep the thread busy when there is a task, no task when the thread sleep.

The management of Runloop is not fully automatic, you must write the thread code at the appropriate time to start the runloop, and respond to the received event. Cocoa and Core framework provides runloop object for developers to configure and manage the thread runloop. However, your application does not need to create these objects, the app framework has been automatically set up in the process of the start and run the runloop.

The following sections provide more information about run loops and how to configure run loops in applications, more information about runloop objects to view NSRunLoop Class Reference and CFRunLoop Reference

Run Loop analysis

A run loop sounds very similar to its name, it is a thread that you enter into the loop, and the user uses it to run the event handler to respond to the event. Your code controls the true loop portion of the runloop implementation. In other words, your code provides for or while to drive run loop. In your loop, you use a run loop object to start the event handler code that can receive events and call the installed event handler.

Runloop receives events from two different types of sources, input source is responsible for distributing asynchronous events, messages are usually from other threads or a different application. The timer source distributes synchronization events that occur at the scheduled time points or repeat intervals. Two types of event sources are used to handle incoming events in an application specific program processing.

3-1 icon shows the concept structure of runloop and various kinds of event source, input source asynchronously sends events to the corresponding process, and lead to the runUntilDate: method is in a specific thread related run loop runloop makes the call termination, the timer will give the event source to the processing procedures, but will not lead to termination of runloop.

IOS RunLoop programming manual (translation)
of a loop and its Structure run sources.png

In addition to processing the input source, the run loops also generates notifications about the behavior of the run loop, which can be received by the registered run-loop observer and can be used for additional processing on the thread using these notifications. You can use Core Foundation to add run loop observers on the thread.

The following sections provide more information about the run loop composition and the run loop processing mode, as well as the notification that runloop has received at different times of processing the event.

1 Run Loop mode

A run loop mode is a collection of sources and timers that will be monitored by the amount of input, as well as an observer set waiting for the run loop notification. Every time you start run loop, “a specified pattern” you show or hermit to run, in the running process of run loop, only the specified pattern and source will be listened to and distribute their event notification (similar, and only the specified mode associated with the observer to get run loop running schedule), input source and other modes will receive any related events stored in the appropriate mode of operation until run loop.

In your code, you can identify the running mode by name, Cocoa and Core Foundation define a default schema and several other generic patterns that can be specified in the code string. You can customize the pattern by simply specifying the string name for the custom pattern. Although your assignment in custom mode names are arbitrary, but these contents are not free, you must ensure that you create the mode to add one or more input source, timer or run loop observer, this custom mode will be available.

You can use the model to filter out unwanted sources in a specific run loop run. In most cases, you will run the code in the “default” mode. A modal panel, however, may run in the “modal” mode, because in this mode, only the source associated with the modal panel can be passed on to the thread. (this is the Mac development, do not understand), for the secondary thread, you can use a custom mode to prevent the low priority of the input source in the time required for a more rigorous operation during the transfer of events.

Note: the input source for the schema and event should be treated differently. For example: you can not use the pattern to match the mouse to press the event or match the keyboard event alone. You can listen to a different set of ports (ports) using the mode, temporarily suspend the timer. You can also change the watcher of the source being monitored and run loop.

Table 3-1 lists the Cocoa and Core Foundationd standard model and the use of descriptive information, name this column lists the constants used in the code specified mode.

IOS RunLoop programming manual (translation)
predefined mode.Png

Default: most of the operations used in the model, in most cases you should open the run loop in this mode, configure the input source.

Connection:Cocoa uses this model to check dependencies with NSConnection objects. You don’t use this pattern yourself

Modal:Cocoa uses this mode to distinguish events sent to the modal panel.
Event tracking:Cocoa uses this mode to restrict input events during mouse drag and other user interface operations.
Common modes: this is a commonly used mode of a combination of the class configuration, and the model related to the input source will also be associated with any one of the patterns within the group. For Cocoa application, the default set includes default, modal, event tracking Core Foundation model, initialization contains only default mode, you can use CFRunLoopAddCommonMode to add custom mode.

2 input source

Input source asynchronous events to distribute your thread, depending on the event source to the input source type, is usually a two types of application input source port to monitor your Mach port based on the input source monitoring custom custom event source. As far as your run loop is concerned, it doesn’t care whether an input source is custom or port based. The system will usually achieve two kinds of input source, you just use it. The only difference between the two sources is how their signals are obtained. Send signal port by kernel based custom source must be manually signaling in other threads.

When you create an input source, you specify one or more modes of operation for it, and the schema determines which input sources will be monitored at any given time. Most of the time you run in default mode, but you can also specify a custom mode. If an input source is not in the scope of the current mode, any event it generates will be saved until run loop runs in the correct mode.

2.1 port based source

Cocoa and Core Foundation provides built-in support for input source based on port to use port related objects and functions to create, for example in Cocoa, you never need to directly create the input source, you only need to create a port object, call the NSPort method to add run loop in port, port object processing input source need to create and configuration.

In Core Foundation, you must manually create the port and run loop input source. In the creation of port and the input source, need to use foreign and not through transparent (no description of the development of the document type (CFMachPortRef), CFMessagePortRef, or CFSocketRef) correlation function to create a suitable object.

For example, how to create and configure a custom port based input source, refer to the 7.7 configuration based on the port of the input source

2.2 custom input source

To create a custom input source, you must use the opacity class CFRunLoopSourceRef related functions in Core Foundation, configure the custom input source to use several callback functions. The Core Foundation will call these functions at different points to configure the source, process the incoming event, and destroy the source when the source is removed from the run loop.

In addition to define custom behavior input source in the event arrives, you must also define the transfer mechanism of the event, this part of the input source to run in a separate thread, and is responsible for providing the input source data, send a signal to the input source in the data preparation processing. The transmission mechanism of the event depends on you, but not too complicated.

For an example of how to create a custom input source, 7.1 define a custom input source. For reference information about custom input sources, see “CFRunLoopSource”.

2.3 Cocoa execute message selector source – (Cocoa Perform Selector Sources)

In addition to the input source port based on Cocoa defines a custom input source allows you to perform selector in arbitrary thread, as input source ports based on selector in the target thread requests are serialized, reducing the number of simultaneous execution of multiple methods in synchronization occurs in a case of a thread the. And the port is different, a perform selector input source after the completion of the selector will automatically remove themselves from run loop.

In 10.5 before the OS X, perform selector input source to the main line of information, after the OS X10.5, you can send messages to any thread.

When a selector is executed on a thread, the thread must have an active run loop, which means that you have been waiting for your code to display the open run loop. Because the main thread has opened its run loop, so the program calls the applicationDidFinishLaunching: to the calling thread, run loop every cycle will queue the perform selector call, not every time run loop recycling a selection in the queue.

Table 3-2 lists the selecors method definition can execute in other threads in the NSObject, because these methods are defined inside the NSObject class, you can be in any of you have access to the use of Objective-C objects including POSIX thread, thread. These methods do not actually create new threads to perform selector.

IOS RunLoop programming manual (translation)
selectors on other Performing threads.png
PerformSelectorOnMainThread:withObject:waitUntilDone: performSelectorOnMainThread:withObject:waitUntilDone:modes:

Perform a specific selector in the main thread of the next run loop loop. These two methods give you the option to block the current thread until the selector is executed.

PerformSelector:onThread:withObject:waitUntilDone: performSelector:onThread:withObject:waitUntilDone:modes:

Performs a specific selector on any thread that is represented by a NSThread object. Also provides the ability to block the current thread until selector is executed.

PerformSelector:withObject:afterDelay: performSelector:withObject:afterDelay:inModes:

Performs selector in the next run loop loop on the current thread, and adds a delay option. Because it waits for the next run loop loop to arrive at selector, these methods provide an automatic small delay from the currently executing code. More than one queue of selector will be in accordance with the order of the implementation of one.

CancelPreviousPerformRequestsWithTarget: cancelPreviousPerformRequestsWithTarget:selector:object:

Allows you to cancel a message sent to the current thread through the performSelector:withObject:afterDelay: or performSelector:withObject:afterDelay:inModes: method method.

See NSObject Class Reference. for more details for each method

2.4 timer source

The timer source sends the event to your thread at a time that is set in advance in advance, and the timer is also a way to inform yourself of something. For example, a search box can use a timer to initialize an automatic search, in the user’s continuous input keyword interval is greater than a certain number of times when the trigger search. The use of delay gives the user an opportunity to print as many words as possible before the search begins.

Although the timer generates a time – based notification, a timer is not a real – time mechanism. Like an input source, the timer associates a specific pattern in your run loop. If a timer is not in the current run loop mode, the timer will not start until you run run loop in the timer supported mode.
is similar, if a timer is opened in the process of executing the run loop code, the timer will wait until the next run loop calls its handler. If run loop is not running, the timer will never start.

You can configure a timer or repeat the event, a repeating timer automatically on a scheduled start time scheduling (fire) began to repeat themselves, and not from the real time timer fire start counting. For example, a timer is set to start at a specific point in time and 5 seconds after that. The scheduled fire time will always fall on the original 5S interval, if the true start time delay. If the start time delay timer that very much missed one or more predetermined fire time points, the timer will only start in a missed period of time, in the time of miss fire, timer will reset the default fire next time.

Configure timer for more reference 7.6 configuration timers, NSTimer Class or CFRunLoopTimer Reference Reference.

3 run loop observer

In contrast to the input source, when a suitable synchronization or asynchronous event occurs, the input source will be fire. and the run loop observer will perform in a special place in the run loop itself by executing it in fire. You can use the run loop viewer to get your thread to process a given event or for run loop will enter the sleep preparation thread. You can also associate the following events with the run loop observer and run loop.

  • Run loop entry
  • Run loop will handle a timer
  • Run loop will handle an input source
  • Run loop is going to sleep
  • Run loop has been awakened, but there is no event to wake up run loop
  • Exit run loop

You can use Core app to add Foundation run loop to create a run observer and loop observer, you create a CFRunLoopObserverRef object of a type, the type of keep track of your custom callback and it concerned run activity loop.

Similar to the timer, the run loop observer can be repeated or single use, a single observer will be removed after its fire in run loop, a repeat of the observer is still attached to the run loop. Single or repeated can be specified at the time of creation.

For an example of how to create a run loop observer, see configuring 6.2 run loop. For reference information, please refer to CFRunLoopObserver.

4 run loop some column events

Every time you run run loop, your thread’s run loop handles the pending event and sends a notification to its observer. The order of processing is very special, that is, the following order.

  • 1 notify the observer run loop has entered the cycle.
  • 2 notify the observer that all ready timers will be fire
  • 3 notify the observer that all non port based input sources will be fire
  • 4.fire all non port based preparation of fire input source
  • 5 if a port based input source is ready and wait for fire. Immediately fire. To the ninth part.
  • 6 notify the watcher thread to sleep
  • 7 thread sleep until any of the following events occur. An event arrives at the port based source timer fire run loop sets the expiration timeout event to show the specified run loop wakeup
  • 8 notify the watcher thread to wake up.
  • 9 handle pending events. If a user-defined timer fire. Process timer events and restart run loop. To step 2 if an input source, fire, passes the event. If the run loop is shown to be awake, but the timeout event has not yet reached, restart run loop to step 2
  • 10 notify observer run loop has exited.

Because the observer from the notification timer and the input source to be in those events actually occurred before being passed over, there may be gaps between the event time and the receipt of the notification time, if in the event of aging is very strict, you can use the sleep and sleep wake up from the notification to help you association the time between events.

Because the timer and other periodic events will be passed when you run run loop, avoid the run loop interrupt on the event. A classic behavior: every time you use a loop to request an event from an application to implement a mouse tracking program. Because your code is directly captured event, rather than let the application of normal distribution of these events, the active timer in your mouse tracking program exits and returns control to the application after the failure.

A run loop can be used run loop object to display the wake, other events can also make run loop wake up. For example, adding other non port based input sources can wake up the run loop so that the input source can be processed immediately, rather than waiting for other events to occur.

5 when will use a run loop

The only thing that needs to be shown to run a run loop scene is to create a helper thread in the application. The application’s main thread run loop is a key part of the infrastructure. So the app framework provides code to run the main thread run loop and automatically open. IOS UIAppliaction run method (or OS X NSApplication) to open an application main loop as part of a number of procedures to start the program flow. If you create an application using the Xcode template project, you should never call these routines.

For the helper thread, you need to decide whether a run loop is necessary, and if so, configure and open it. You do not need to open a thread run loop in any case. For example, if you use a thread to perform certain tasks that are running for a long time and are predefined, you can avoid opening run loop. The purpose of run loops is to apply it in a situation where you want to have more interaction with the thread. For example: if you want to do any of the following things you need to open run loop.

  • Use a port or custom input source to communicate with other threads
  • Use timer on thread
  • Use any performSelector in cocoa applications… Method
  • Threads are not killed for periodic tasks

If you choose to use a run loop, configuration and creation is very simple. As with all thread programming, you specify the end of your helper thread for the right occasion. Generally speaking, it is better to terminate the thread with an exit (exit) than to force the thread to terminate. How to configure and exit run loop description information in 6 using the run loop object

6 use run loop object

A run loop object provides the main interface for adding input sources, timers, observers, and running run loop, each thread has a single run loop object and its associated. In Cocoa, the object is an instance of the NSRunLoop class, which is a pointer to a CFRunLoopRef type in a low-level application.

6.1 get a run loop object

The only way to get the current thread’s run loop is to use the following method:

  • In Cocoa applications, using the NSRunLoop class method currentRunLoop returns a NSRunLoop object
  • Use the CFRunLoopGetCurrent function

Although these two are not free bridging types, you can get a CFRunLoop type from a NSRunLoop object if necessary. Obtained by NSRunLoop getCFRunLoop method, and then passed to Core Foundation code. Because the two objects refer to the same run loop, you can call it as needed.

6.2 configure run loop

When you open the run loop on a secondary thread, you must add at least one input source or a timer to the run loop. If a run loop does not have any source to monitor, it will immediately exit. Refer to Configuring Run Loop Sources

In addition to adding the input source, you can add the run loop observer, and use their run loop monitoring in different stages of operation, add observation object to create a CFRunLoopObserverRef type, added to the run loop with CFRunLoopAddObserve function. Observers must be created with Core Foundation, even in Cocoa applications.

3-1 is a code that binds an observer’s thread to open its run loop. This example shows how to create a run loop observer, so the code simply creates an observer to monitor all activities of the run loop. The basic handler (not shown) simply records the activity of the run loop while processing the timer request.

Listing 3-1 a run loop Creating observer

- (void) threadMain The application uses garbage {/ / collection, so no autorelease pool is needed. NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop] a run loop observer; / / Create and attach it to the run loop. CFRunLoopObserverContext context = {0, self, NULL, NULL, NULL}; CFRunLoopObserverRef observer = CFRunLoopObserverCreate (kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0 &, myRunLoopObserver, context); & if; (observer) {CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop]; CFRunLoopAddObserver (cfLoop, observer, kCFRunLoopDefaultMode);} / / Create and schedule the timer. [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selec Tor (doFireTimer:) userInfo:nil repeats:YES] NSInteger; loopCount = 10; do the run {/ / Run loop 10 times to let the timer fire. [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; loopCount--; while (loopCount);}}

When configuring a run thread for a long time, it is best to add an input source to receive the loop message. Even if you can enter a run timer with only one timer, once the timer fire, it is invalid. Will cause run loop to exit. Binding a repetitive timer can make run loop run over a long period of time. But you need a regular trigger timer to wake up your thread. This is actually another form of polling. Instead, an input source waits for an event to occur, and the thread will remain dormant until the next time.

6.3 open run loop

It is necessary to open the run loop in the application only for the auxiliary thread, and the run loop must have at least one input source or timer to monitor, and if none of them will end immediately.

Here are a few ways to open run loop:

  • Unconditional (Unconditionally)
  • With time limit set (With a set time limit)
  • In a specific mode (In a particular mode)

Unconditional access to run loop is the easiest option, but it is also the most unnecessary. The unconditional operation of the run loop puts the thread in a permanent loop, with very little control over the run loop itself. You can add or remove the input source or timer, but the only way to stop the run loop is to kill it, and there is no way to run run loop in the custom mode.

Rather than unconditionally start run loop, it is better to set a timeout for run loop to run better. When you use a timeout value, run loop will continue to run until the time of the event or the allocation of time to run out. If an event arrives, the event will be distributed to the handler to process, and then run loop exit. If the assigned time expires, you can simply restart the run loop or take the time to deal with anything you need.

In addition to setting the timeout event value, you can also run the run loop to the specified loop mode, and the mode and timeout values are not mutually exclusive and can be added at the same time as run. Mode limits the type of input source passed to the run loop event. (details 1 Run Loop mode.)

3-2 is the main code structure of a single thread, the key part is the case shows the basic structure of run loop, you can actually add run to loop input source and then repeat their timer from multiple routines in a call to start run loop. Each time the run loop routine returns, you check to see if there are any conditions that might cause the thread to end. This example uses the Core Foundation run loop program, so it can check the return results and know why run loop quit, if you use the Cocoa NSRunLoop method can also be used in a similar way to run run loop and do not check the return value in the 3-14..

Listing 3-2 a run Running loop

- (void) skeletonThreadMain up an autorelease {/ / Set pool here if not using garbage collection. BOOL done = NO; / / Add your sources or timers to the run loop and do any other setup. do the run loop {/ / Start but return after each source is handled. SInt32 result = CFRunLoopRunInMode (kCFRunLoopDefaultMode, 10, YES); If a source explicitly stopped the / run loop, or if there are no or go ahead / / sources timers, and exit. if ((result = = kCFRunLoopRunStopped) || (result = = kCFRunLoopRunFinished) done = YES); / / Check for any other exit conditions here and set the variable as needed. / / done} while (done!) Clean up code here. Be; / / sure To release allocated autorelease pools.} (any)

It is possible to run a run loop recursively, in other words, you can call CFRunLoopRun, CFRunLoopRunInMode, or any other NSRunLoop method in the input or timer handler. When you do this, you can use any of the patterns you want to run the nested run loop, including the use of the outer run loop mode.

6.4 exit Run Loop

There are two ways to end run loop before making a run loop event.

  • Configure a timeout time for run loop.
  • Tell run loop to stop

The use of timeout is certainly the best, you can manage it. Specifies the timeout period for run loop to end all of its usual operations before exiting, including informing the observer.

CFRunLoopStop function with the display of the run loop and the effect of the time set by the timeout is similar. Run loop will send out all the remaining run loop related notifications and then exit, the difference is that you can use the technology on unconditional run loop

While removing the run loop input source and the timer will also cause run loop to exit, this is not a reliable way to stop run loop. Some system programs add run loop to the input source to handle the necessary events. Because your code may not be aware of the presence of these input sources, it cannot remove these input sources, which will prevent run loop from exiting.

7 thread security and Run Loop objects

The difference in thread security depends on the API you use to operate run loop, and the function in Core Foundation is usually thread safe and can be called by any thread. However, if you are performing an operation on the run loop configuration, it is still a good practice to operate as much as possible from the corresponding run loop thread.

Cocoa NSRunLoop class is not as safe as thread in Core Foundation, if you use NSRunLoop to modify your run loop, you should only operate on the corresponding run loop thread. Adding an input source or timer to an run loop that is not a current thread will cause your code to crash or produce unpredictable behavior.

7 configure Run Loop resources

The following sections of the code are examples of how to set different types of input sources (Cocoa and Foundation)

7.1 define a custom input source

Create a custom input source that contains the following options

  • Enter the information the source wishes to process
  • A scheduler allows interested customers (client) to know how to get in touch with your input source
  • A handler is responsible for executing a request from a client (client)
  • A cancel program that lets you enter an invalid source

Because you create a custom input source to handle custom information, the actual configuration of the design is flexible. The scheduler and the cancel program are key programs, your custom input source is almost always needed, and most of the rest of the input source behavior takes place outside of these programs. For example, you can define the mechanism by which data is passed to your input source and the presence of the input source to another thread.

Figure 3-2 is a custom input source configuration case. In this case, the main thread of the program maintains a reference command buffer for the input source, a custom input source, and a reference to the run loop where the input source is located. When the main thread has a task to be delivered to the worker thread, it sends a command and the information required by the worker thread for all the tasks that are required. (because the main thread and thread has access to the command buffer access permissions must be synchronized) once by the wakeup command handler run loop calls the input source to the command in the command buffer.

IOS RunLoop programming manual (translation)
3-2 operates a custom input source.Png

The following sections explain the implementation of the above icon custom input source, and the key to the realization of the code

7.2 define input sources

Customizing an input source requires the use of the Core Foundation code to configure the run loop resource and attach it to the run loop. Although the basic handler is a C function, it does not rule out the need to use OC or C++ to encapsulate the functions to implement your code.

The input source, shown in figure 3- 2, uses the OC object to manage a command line buffer that coordinates run loop. 3-3 shows the definition of this object, the RunLoopSource object manages a command line buffer to receive messages from other threads in the buffer. 3-3 also shows the definition of the RunLoopContext object, which is a real container object that is used to pass a RunLoopSource object and an run loop to the application’s main thread.

Listing 3-3 custom input source object The definition

@interface RunLoopSource: NSObject {CFRunLoopSourceRef runLoopSource; NSMutableArray* commands;} - (ID) - (void) init; addToCurrentRunLoop; invalidate; / / - (void) method - Handler (void) sourceFired interface for registering commands; / / Client to process (void) addCommand: (NSInteger) command withData: (ID) - (data; void) fireAllCommandsOnRunLoop: (CFRunLoopRef) runloop; @end are the CFRunLoopSourceRef callback functions. / These void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef RL, CFStringRef mode); void RunLoopSourcePerformRoutine (void *info); void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef RL, CFStringRef mode); / / RunLoopContext is a container object used during registration of the input source. @interfa CE RunLoopContext: NSObject {CFRunLoopRef runLoop; RunLoopSource* source;} @property (readonly) CFRunLoopRef runLoop; RunLoopSource* source; @property (readonly) - (ID) initWithSource: (RunLoopSource*) SRC andLoop: (CFRunLoopRef) loop; @end

Although the custom input source data is OC code management, but the input source and the run loop association requires a callback function based on C in the code, will be the first of these functions on what you will call, run loop source and run loop binding in 3-4, because only one client (input source Zhu Xiancheng) it is an information to their application agent in that thread on the registration procedures in their use of scheduling function. When the contemporary ideal and the input source get in touch, the RunLoopContext object is used.

Listing 3-4 a run loop Scheduling source

Void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef RL, CFStringRef mode) {RunLoopSource* = obj (RunLoopSource*) info; AppDelegate* del = [AppDelegate sharedAppDelegate]; RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl] [del performSelectorOnMainThread:@selector (registerSource:); withObject:theContext waitUntilDone:NO];}

One of the most important callback procedures is to use custom data when the input source receives a signal, and the 3-5 shows the callback code that executes the RunLoopSource object. This function simply forwards the work request to the sourceFired method, which will then be processed by any command in the command buffer.

Listing 3-5 work in the input Performing source

Void RunLoopSourcePerformRoutine (void *info) {obj = (RunLoopSource*) info; [obj sourceFired];}

If you use the CFRunLoopSourceInvalidate function to remove the input source, the system will call the source code. You can use this code to inform the customer that your input source is no longer valid and that they should remove all of its associated. 3-6 is a callback code for RunLoopSource object registration. This function sends another RunLoopContext object to the application agent, but this is the request agent to remove the run loop source.

Listing 3-6 an input Invalidating source

Void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef RL, CFStringRef mode) {RunLoopSource* = obj (RunLoopSource*) info; AppDelegate* del = [AppDelegate sharedAppDelegate]; RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl] [del performSelectorOnMainThread:@selector (removeSource:); withObject:theContext waitUntilDone:YES];}

Note: application agent registerSource: and removeSource: method in Coordinating with of the Input Clients Source

7.3 add input source on run loop

3-7 shows RunLoopSource’s init and addToCurrentRunLoop methods. The init method creates must adhere to RunLoop CFRunLoopSourceRef non transparent type object, it passes through the RunLoopSource object itself as context information, so the callback procedure has a pointer pointing to the object. The input source installation work not in the work thread calls the addToCurrentRunLoop method before the addToCurrentRunLoop call the RunLoopSourceScheduleRoutine callback function will be called once the input source is added to the run loop thread can run its run loop to wait for the event.

Listing 3-7 the run loop Installing source

- (ID) init {CFRunLoopSourceContext context = {0, self, NULL, NULL, NULL, NULL, NULL, RunLoopSourceScheduleRoutine, & RunLoopSourceCancelRoutine, RunLoopSourcePerformRoutine}; runLoopSource = CFRunLoopSourceCreate (NULL, 0; commands, & context) = [[NSMutableArray alloc] init]; return self;} - (void addToCurrentRunLoop) {CFRunLoopRef runLoop = CFRunLoopGetCurrent (); CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopDefaultMode);}

7.4 coordinate the input source of the customer

In order to enter the input source, you should be able to skillfully control it and send a signal to another thread. The main point of the input source lets the thread associated with it sleep until something is done. So it is a real need for other threads to get the information of the input source and communicate with the input source.

A way to notify the customer of the input source is to send a registration request when the source is installed on the run loop for the first time. You can register multiple clients for an input source, or simply register with a number of central institutions, and then put the input source to interested customers. 3-8 shows the application proxy registration and registration method in the scheduling function of the RunLoopSource object is invoked to perform the method of receiving the RunLoopSource object provided by the RunLoopContext object, and add it to the list of sources, the following code also includes the input source from the run loop to remove unregisters.

Listing 3-8 Registering removing input source with the application and an delegate

- (void) registerSource: (RunLoopContext*) sourceInfo; {[sourcesToPing addObject:sourceInfo];} - (void) removeSource: (RunLoopContext* sourceInfo) {ID objToRemove = nil; for (RunLoopContext* context in sourcesToPing if (context) {[isEqual:sourceInfo]) {objToRemove}} = context; break; if (objToRemove) [sourcesToPing removeObject:objToRemove];}

Callback function call method in the above 3-4 and 3-6

7.5 signal to the input source

When a customer sends its data to the input source, the source must be sent to the signal to wake up its run loop, the input source to send a signal to let run loop know that the input source is ready, waiting for processing. Because a signal occurs when the thread may be sleeping, you should always show the wake of run loop. Failure to do so may result in a delay in processing the input source data.

3-9 shows the fireCommandsOnRunLoop method of the RunLoopSource object, which is called by the customer when they prepare for processing the input buffer data.

Listing 3-9 up the run Waking loop

- (void) fireCommandsOnRunLoop: (CFRunLoopRef) runloop {CFRunLoopSourceSignal (runLoopSource); CFRunLoopWakeUp (runloop);}

Note: you should not try to process signals sent by SIGHUP or other types of custom input source, Run Loop Core Foundation used to wake up signal function is not safe, should not use the signal processing program in the application of. For more information about the signal handler routine, see the sigaction manual page.

7.6 configuration timer

To create a timer source, you just create a timer object and schedule it in Run Loop. In Cocoa, you can use the NSTimer class to create a new timer object, and in Core Foundation, you can use the CFRunLoopTimerRef type. Internally, the NSTimer class is just an extension of the Core Foundation, which provides some convenient features, such as the ability to create and schedule timers using the same method.

In Cocoa, you can use one of the following methods to create and schedule a timer:

ScheduledTimerWithTimeInterval:target:selector:userInfo:repeats: scheduledTimerWithTimeInterval:invocation:repeats:

These methods create a timer and add it to the current thread’s Run Loop by default mode (NSDefaultRunLoopMode). If you want to create a NSTimer object and then use the NSRunLoop addTimer:forMode method to add it to the run loop, you can manually schedule the timer. These two technologies are basically the same, but give you different levels of control timer configuration. For example, if you create a timer and manually add it to the run loop, you can use this mode in addition to the default mode. Listing 3-10 shows how to use the two techniques to create a timer. The initial delay of the first timer is 1 second, but then the timing fire every 0.1 seconds. The second timer starts at the first 0.2 seconds of delay, and then fire the fire for once every 0.2 seconds.

Listing 3-10 and scheduling timers using Creating NSTimer

NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; Create and schedule the first timer. / NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0]; NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate interval:0.1 target:self selector:@selector (myDoFireTimer1:) userInfo:nil repeats:YES]; [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; Create and schedule the second timer. / [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector (myDoFireTimer2:) userInfo:nil repeats:YES];

Listing 3-11 shows the code required to configure the timer using the Core Foundation function. Although this example does not pass any user – defined information in the context structure, you can use this structure to pass any custom data needed by the timer. For more information about the contents of this structure, see the description in the CFRunLoopTimer reference.

CFRunLoopRef = CFRunLoopGetCurrent (runLoop); CFRunLoopTimerContext context = {0, NULL, NULL, NULL, NULL}; CFRunLoopTimerRef timer = CFRunLoopTimerCreate (kCFAllocatorDefault, 0.1, 0.3, 0, 0, & myCFTimerCallback, & context); CFRunLoopAddTimer (runLoop, timer, kCFRunLoopCommonModes);

7.7 configure port based input sources

Both Cocoa and Core Foundation provide port based objects for communication between threads or processes. The following sections describe how to use several different types of ports to set up port communication.

7.7.1 configuration NSMachPort object

To create a local connection to a NSMachPort object, you will create a port object and add it to the Run Loop of the main thread. When the helper thread is started, the same object is passed to the entry point function of the thread. The auxiliary thread message can be sent back to the main thread using the same object.

7.7.2 to achieve the main thread code

Listing 3-12 shows the main thread code to start the worker thread. Because the Cocoa framework for intervention to perform many steps to configure the port and run loop, so launchThread method was significantly shorter than the equivalent Core Foundation configuration (list 3-17); however, their behavior is almost the same. One difference is that the method is not to send the name of the local port to the worker thread, but to send the NSPort object directly.

Listing 3-12 thread launch Main method

- (void) launchThread myPort port] {NSPort* = [NSMachPort; if (myPort) class handles incoming {/ / This port messages. [myPort setDelegate:self] the port as; / / Install an input source on the current run loop. [[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode] the thread. Let; / / Detach the worker release the port. [NSThread detachNewThreadSelector:@selector (LaunchThreadWithPort:) toTarget:[MyWorkerClass class] withObject:myPort];}}

In order to create a two-way communication channel between threads, you may want the worker thread to send its own local port to the main thread in the login message. Receiving the check in message lets your main thread know that everything is going smoothly when you start the second thread, and you can send more messages to the thread. Listing 3-13 shows the handlePortMessage of the main thread: method. This method is called when the data reaches its own local port. When a message arrives, the method retrieves the port of the secondary thread from the port message and saves it for later use.

Listing 3-13 Mach port Handling messages

#define kCheckinMessage Handle responses from the worker 100 / thread. - (void) handlePortMessage: (NSPortMessage *) portMessage unsigned int [portMessage msgid] {message = NSPort*; distantPort = nil; if (message = = kCheckinMessage) {/ / Get the worker thread s communications port. distantPort = "[portMessage sendPort] and save the; / / Retain worker port for later use. [self storeDistantPort:distantPort];} else {/ / Handle other messages.}}

7.7.3 to achieve the secondary thread code

For the worker thread, you must configure the thread and send the information back to the main thread using the specified port.
listing 3-14 shows the code for setting the worker thread. To create an auto release pool for the thread, the method creates a worker object to drive the thread execution. Object sendCheckinMessage: method (as shown in listing 3-15) to create a local port thread to work, and a signed message back to the main thread.

Listing 3-14 the worker using Mach thread Launching ports

(void) + LaunchThreadWithPort: (ID) inData pool alloc] init] {NSAutoreleasePool* = [[NSAutoreleasePool; / / Set up the connection between this thread and the main thread. NSPort* distantPort (NSPort*) = inData workerObj = [[self alloc]; MyWorkerClass* init]; [workerObj sendCheckinMessage:distantPort]; [distantPort release]; Let the run loop process things. / do currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] {[[NSRunLoop while;} ([workerObj! ShouldExit]); [workerObj release]; [pool release];}

When using NSMachPort, local and remote threads can use the same port object to communicate between threads. In other words, a local port object created by a thread will be a remote port object for another thread. The
listing 3-15 shows the checking routine for the secondary thread. The method of setting their own local port for future communication, then send a check message back to the main thread. This method uses the port object received in LaunchThreadWithPort as a message destination.

Listing 3-15 the check-in using Mach message Sending ports

- (void) sendCheckinMessage: (NSPort*) outPort and save the {/ / Retain remote port for future use. [self setRemotePort:outPort] and configure the; / / Create worker thread port. NSPort* myPort = [NSMachPort port]; [myPort setDelegate:self]; NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode] "Create the check-in message. NSPortMessage*; / / messageObj = [[NSPortMessage alloc] initWithSendPort:outPort receivePort:myPort components:nil] if (messageObj); configuring the message {/ / Finish and send it immediately. [messageObj setMsgId:setMsgid:kCheckinMessage]; [messageObj sendBeforeDate:[NSDate date]];}}

7.7.4 configure a NSMessagePort object

To create a local connection to a NSMessagePort object, you cannot simply pass port objects between threads. Remote message port must be named. In Cocoa, you may need to register a local port with a specific name, and then pass it to the remote thread so that it can get the appropriate port object to communicate. Listing 3-16 shows the port creation and registration process to use message ports.

Listing 3-16 a message Registering port

NSPort* localPort = [[NSMessagePort alloc] init] the object and add; / / Configure it to the current run loop. [localPort setDelegate:self]; [[NSRunLoop currentRunLoop] addPort:localPort forMode:NSDefaultRunLoopMode] the port using; / / Register a specific name. The name must be unique. NSString* localPortName [NSString stringWithFormat:@ = "MyPortName"]; [[NSMessagePortNameServer sharedInstance] registerPort:localPort name:localPortName];

Configuration of port based input source in 7.7.6 Core Foundation

This section describes how to use Core Foundation to set up a two-way communication channel between the application’s main thread and the worker thread. Listing 3-17 shows the code used by the application’s main thread to start the worker thread. The first thing to do is to set up a CFMessagePortRef opaque type to listen to messages from the worker thread. The worker thread needs to be connected to the port name in order to pass the string value to the entry point function of the worker thread. The port name is unique in the current user context; otherwise, you may encounter a conflict.

Listing 3-17: attach the Core Foundation message port to the new thread

#define kThreadStackSize (8 *4096) OSStatus MySpawnThread (a local port) {/ / Create for receiving responses. CFStringRef myPortName; CFMessagePortRef myPort; CFRunLoopSourceRef rlSource; CFMessagePortContext context = {0, NULL, NULL, NULL, NULL}; Boolean shouldFreeInfo; Create a string with the port / name. myPortName = CFStringCreateWithFormat (NULL, NULL, CFSTR ("com.myapp.MainThread")); / / Create the port. myPort = CFMessagePortCreateLocal (NULL, myPortName, & MainThreadResponseHandler, & context, & shouldFreeInfo); if (myPort! = NULL) {/ / The port was successfully created. create a R / / Now UN loop source for it. rlSource = CFMessagePortCreateRunLoopSource (NULL, myPort, 0); if (rlSource) the source to {/ / Add the current run loop. CFRunLoopAddSource (CFRunLoopGetCurrent), (rlSource, kCFRunLoopDefaultMode); / / Once installed these can be freed. CFRelease (myPort); CFRelease (rlSource);}} / / Create the thread and continue processing. MPTaskID taskID; return (MPCreateTask (& ServerThreadEntryPoint (void*), myPortName, kThreadStackSize, NULL, NULL, NULL, 0, & taskID));}

In the case of the installation port and start the thread, the main thread can continue its normal execution while waiting for the thread to be checked in. When the incoming message arrives, it will be assigned to the MainThreadResponseHandler function of the main thread, such as listing 3- 18. This function extracts the port name of the worker thread and creates the future communication pipeline.
Listing Receiving the checkin 3-18 message

#define kCheckinMessage 100 thread port message handler / / Main CFDataRef MainThreadResponseHandler (CFMessagePortRef local, SInt32 msgid, CFDataRef data, void* info) {if (msgid = = kCheckinMessage) {CFMessagePortRef messagePort; CFStringRef threadPortName; CFIndex bufferLength = CFDataGetLength (data); UInt8* buffer = CFAllocatorAllocate (NULL, bufferLength, data, CFDataGetBytes (0) (CFRangeMake; 0, bufferLength), buffer); threadPortName = CFStringCreateWithBytes (NULL, buffer, bufferLength, kCFStringEncodingASCII, FALSE); / / You must obtain a remote message port by name. messagePort = CFMessagePortCreateRemot E (NULL, threadPortName (CFStringRef)); if (messagePort) and save the {/ / Retain thread comm port for future reference. s AddPortToListOfActiveThreads (messagePort); / / Since the port is retained by the previous function, release it here. (messagePort / CFRelease);} / / Clean up. CFRelease (threadPortName); CFAllocatorDeallocate (NULL, buffer);} else {other} / / Process messages. return NULL;}

After configuring the main thread, the only remaining is the newly created worker thread to create your own port and check in. Listing 3-19 shows the entry point function for the worker thread. The function to extract the main thread port name, and use it to create a remote connection back to the main thread. The function then creates a local port for itself, installs the port on the thread’s run loop, and sends the incoming message to the primary thread containing the local port name.

Listing 3-19 up the thread Setting structures

OSStatus ServerThreadEntryPoint (void* param the remote port) {/ / Create to the main thread. CFMessagePortRef mainThreadPort; CFStringRef portName (CFStringRef) = param; mainThreadPort = CFMessagePortCreateRemote (NULL, portName); / / Free the string that was passed in param. CFRelease (portName); / / Create a port for the worker thread. CFStringRef myPortName (NULL = CFStringCreateWithFormat NULL, CFSTR ("com.MyApp.Thread-%d"), MPCurrentTaskID ()); / / Store the port in this thread s context info for later reference. "CFMessagePortContext context = {0, mainThreadPort, NULL, NULL, NULL}; Boolean shouldFreeInfo Boolean; shouldAbort = TRUE; CFMessagePortRef = CFMessagePortCreateLocal (N myPort ULL, myPortName, & ProcessClientRequest, & context, & shouldFreeInfo); if (shouldFreeInfo) Couldn't create a local {/ / port so kill the thread. MPExit (0);} CFRunLoopSourceRef rlSource = CFMessagePortCreateRunLoopSource (NULL, myPort, 0); if (! RlSource create a local Couldn't) {/ / port. So kill the thread. MPExit (0);} / / Add the source to the current run loop. CFRunLoopAddSource (CFRunLoopGetCurrent), (rlSource, kCFRunLoopDefaultMode); / / Once installed these can be freed. CFRelease (myPort); CFRelease (rlSource); / / Package up the port name and send the check-in message. CFD AtaRef returnData = nil; CFDataRef outData; CFIndex stringLength = CFStringGetLength (myPortName); UInt8* buffer = CFAllocatorAllocate (NULL, stringLength, 0; CFStringGetBytes (myPortName), CFRangeMake (0, stringLength), kCFStringEncodingASCII, 0, FALSE, buffer, stringLength, NULL); outData = CFDataCreate (NULL, buffer, stringLength); CFMessagePortSendRequest (mainThreadPort, kCheckinMessage, outData, 0.1, 0, NULL, NULL); / / Clean up thread data structures. CFRelease (outData); CFAllocatorDeallocate (NULL, buffer); / / Enter the run loop. (CFRunLoopRun);}

Once into its run loop, all future events sent to the thread port will be handled by the ProcessClientRequest function. The implementation of this function depends on the type of thread that is not displayed.