Explanation of Objective-C's run loop, objective-cloop

Source: Internet
Author: User

Explanation of Objective-C's run loop, objective-cloop

Objective-C run loop

 

I don't know if you have ever thought about this problem. An application is put there after it starts to run. If you don't perform any operations on it, the application is just as static and will not take any spontaneous action, however, if we click a button on the interface, the corresponding button RESPONSE event will occur at this time. It makes us feel like an application is always on standby. When no one is operating, it is always resting. When it is working, it can respond immediately. In fact, this is the credit of run loop.

I. Thread and run loop

1.1 thread Task Type

Let's talk about threads. Some threads execute tasks in a straight line from the start point to the end point, while other threads want to work in a circle and keep repeating until they are terminated in some way. A straight line thread is like a simple Hello World. After printing is completed, its life cycle ends, like a flash; a circle is like an operating system and runs until you shut down. In IOS, the Round Thread is implemented through a non-stop loop of run loop.

1.2 relationship between threads and run loop

Run loop, as in its name, loop indicates a loop, and put it together with run indicates a loop that has been running. In fact, the run loop is closely linked to the thread. It can be said that the run loop is generated for the thread, and there is no need for it to exist without a thread. Run loops is the basic framework of the thread. Both Cocoa and CoreFundation provide the run loop object for convenient configuration and management of the thread (the following uses Cocoa as an example ). Each thread, including the main thread of the program, has a corresponding run loop object.

1.2.1 The run loop of the main thread is started by default.

In iOS applications, the program starts with the following main () function:

Int main (int argc, char * argv [])

{

@ Autoreleasepool {

Return UIApplicationMain (argc, argv, nil, NSStringFromClass ([appDelegate class]);

}

}

The focus is on the UIApplicationMain () function. This method sets a nsunloop object for main thread. This explains why our application can rest when no one is operating, when it needs to work, it can respond immediately.

1.2.2 For other threads, run loop is not started by default. If you need more thread interactions, You can manually configure and start it, this is not required if the thread only executes a long-time confirmed task.

1.2.3 In any Cocoa program thread, you can use:

Nsunloop * runloop = [nsunloop currentRunLoop];

To obtain the run loop of the current thread.

1.3 Description of run loop

1.3.1 The nsunloop class in Cocoa is NOT thread-safe.

We cannot operate the run loop object of another thread in another thread, which may cause unexpected consequences. Fortunately, the opaque class CFRunLoopRef in CoreFundation is thread-safe, and the two types of run loop can be used together. In Cocoa, the nsunloop class can be implemented through the instance method:

-(CFRunLoopRef) getCFRunLoop;

Obtain the corresponding CFRunLoopRef class to achieve thread security.

1.3.2 The management of Run loop is not completely automatic.

We still need to design the thread code to start the run loop at appropriate times and correctly respond to input events, provided that the run loop is used in the thread. In addition, we also need to use the while/for statement to drive the run loop to run cyclically. The following code successfully drives a run loop:

BOOL isRunning = NO;

Do {

IsRunning = [[nsunloop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDatedistantFuture];

} While (isRunning );

1.3.3 Run loop is also responsible for the creation and release of autorelease pool.

Many automatically released objects are often used in projects using manual memory management. If these objects cannot be instantly released, the memory usage will increase dramatically. Run loop does this for us. Every time a running loop ends, it releases the autorelease pool and all automatically released type variables in the pool are released.

1.3.4 advantages of Run loop

A run loop is an event processing loop that constantly monitors and processes input events and distributes them to the corresponding targets for processing. If you only want to implement this function, you may think that a simple while loop can be implemented. Do you need to make a complicated mechanism with great effort? Obviously, Apple's architects don't have a dry meal. They thought about it for a long time.

First, nsunloop is a more advanced message processing mode, which makes it better to abstract and encapsulate the message processing process, in this way, you do not need to process some very trivial and low-level specific messages. In the nsunloop, each message is packaged in the input source or timer source (see the following article.

Second, it is also very important to use the run loop to enable your thread to work when it is working and sleep when it is not working, which can greatly save system resources.

 

2. Run loop knowledge points

2.1 input event Source

Run loop receives input events from two different sources: input source and timer source ). Both origins use a specific processing routine of the program to process events that arrive. Figure-1 shows the concept and structure of the run loop and various sources.


It should be noted that when you create an input source, you need to allocate it to one or more modes in the run loop (what is the mode, which will be discussed below ). Mode only affects the source of the listener in a specific event. In most cases, run loop runs in default mode, but you can also make it run in custom mode. If a source is not listened to in the current mode, any messages generated by the source are transmitted only when the run loop runs in the associated mode.

Figure-1 Structure and Input Source Type of Runloop

 

2.1.1 input source)

Transmits asynchronous events. messages are generally sent from other threads or programs. Input the source to pass the asynchronous message to the corresponding processing routine, and call runUntilDate: Method to exit (called by the relevant nsunloop object in the thread ).

2.1.1.1 port-based Input Source

Port-based input sources are automatically sent by the kernel.

Cocoa and Core Foundation Support Port-based sources created by using port-related objects and functions. For example, in Cocoa, you never need to directly create an input source. You only need to create a port object and add the port to the run loop using the NSPort method. The port object handles the creation and configuration of the Input Source.

At Core Foundation, you must manually create a port and its run loop source. We can use port-related functions (CFMachPortRef, CFMessagePortRef, CFSocketRef) to create appropriate objects. The following example shows how to create a port-based input source, add it to the run loop, and start it:

VoidcreatePortSource ()

{

CFMessagePortRef port = CFMessagePortCreateLocal (kCFAllocatorDefault, CFSTR ("com. someport"), myCallbackFunc, NULL, NULL );

CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource (kCFAllocatorDefault, port, 0 );

CFRunLoopAddSource (CFRunLoopGetCurrent (), source, kCFRunLoopCommonModes );

While (pageStillLoading ){

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

CFRunLoopRun ();

[Pool release];

}

CFRunLoopRemoveSource (CFRunLoopGetCurrent (), source, kcfrunloopdefamode );

CFRelease (source );

}

2.1.1.2 custom Input Source

Custom input sources must be manually sent from other threads.

To create a custom input source, you must use the CFRunLoopSourceRef function in the Core Foundation. You can use the callback function to configure custom input sources. Core Fundation calls the callback function in different places of the configuration source to process the input event and clear it when the source is removed from the run loop.

In addition to defining the behavior of custom input sources when an event arrives, you must also define the message transmission mechanism. This part of the source runs in a separate thread, and is responsible for transmitting data to the source when the data is waiting for processing and notifying it to process the data. The definition of the message transmission mechanism depends on you, but it is better not to be too complicated. An example of creating and starting a custom input source is as follows:

VoidcreateCustomSource ()

{

CFRunLoopSourceContext context = {0, NULL, NULL };

CFRunLoopSourceRef source = CFRunLoopSourceCreate (kCFAllocatorDefault, 0, & context );

CFRunLoopAddSource (CFRunLoopGetCurrent (), source, kcfrunloopdefamode );

While (pageStillLoading ){

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

CFRunLoopRun ();

[Pool release];

}

CFRunLoopRemoveSource (CFRunLoopGetCurrent (), source, kcfrunloopdefamode );

CFRelease (source );

}

2.1.1.3selector source on cocoa

Besides port-based sources, Cocoa defines custom input sources, allowing you to execute the selector method in any thread. Like a port-based source, executing a selector request will serialize the target thread, slowing down synchronization problems that may occur when many methods are allowed on the thread. Unlike port-based sources, a selector is automatically removed from the run loop after execution.

When selector is executed on other threads, the target thread must have an active run loop. For the thread you created, this means that the thread will not execute the selector method before you explicitly start the run loop, but will remain in sleep state.

The NSObject class provides a selector method similar to the following:

-(Void) specified mselecw.mainthread :( SEL) aSelector withObject :( id) argwaitUntilDone :( BOOL) wait modes :( NSArray *) array;

 

2.1.2 timing source)

The scheduled source transmits messages synchronously at a preset time point. These messages are generated at a specific time or at repeated time intervals. The scheduled source directly transmits the message to the processing routine and does not immediately exit the run loop.

It should be noted that although the timer can generate time-based notifications, it is not a real-time mechanism. Like the input source, the timer is also related to the specific mode of your run loop. If the mode in which the timer is located is not currently monitored by the run loop, the timer will not start until the run loop runs in the corresponding mode. Similarly, if the timer starts to process an event in the run loop, the timer will wait until the next run loop starts the corresponding processing program. If the run loop is no longer running, the timer will never start.

There are two ways to create a timer Source,

Method 1:

NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 4.0

Target: self

Selector: @ selector (backgroundThreadFire :) userInfo: nil

Repeats: YES];

[[Nsunloop currentRunLoop] addTimer: timerforMode: NSDefaultRunLoopMode];

 

Method 2:

[NSTimer scheduledTimerWithTimeInterval: 10

Target: self

Selector: @ selector (backgroundThreadFire :)

UserInfo: nil

Repeats: YES];

2.2 RunLoop observer

The source is triggered when an appropriate synchronous or asynchronous event occurs, while the run loop observer is triggered at a specific time when the run loop itself runs. You can use the run loop observer to prepare for processing a specific event or a thread that enters sleep. You can associate the run loop observer with the following events:

1. Runloop entry

2. When does Runloop process a timer?

3. When does Runloop process an input source?

4. When does Runloop go to sleep?

5. events to be processed before Runloop is awakened

6. Runloop termination

Similar to the timer, you can specify that the run loop observer can be used only once or cyclically during creation. If it is used only once, after it is started, it will remove itself from the run loop, while the observer of the loop will not. Define the observer and add it to the run loop. You can only use Core Fundation. The following example demonstrates how to create an observer for the run loop:

-(Void) addObserverToCurrentRunloop

{

// The application uses garbage collection, so noautorelease pool is needed.

Nsunloop * myRunLoop = [nsunloop currentRunLoop];

// Create a run loop observer and attach it to the runloop.

CFRunLoopObserverContext context = {0, self, NULL };

CFRunLoopObserverRef observer = CFRunLoopObserverCreate (kCFAllocatorDefault,

KCFRunLoopBeforeTimers, YES, 0, & myRunLoopObserver, & context );

If (observer)

{

CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop];

CFRunLoopAddObserver (cfLoop, observer, kCFRunLoopDefaultMode );

}

}

Among them, kCFRunLoopBeforeTimers indicates that the listener timer is selected to trigger the pre-processing event, and the following YES indicates the loop listener.

 

2.3 RunLoop event queue

Each time you run the run loop, the run loop of your thread automatically processes unprocessed messages and notifies relevant observers. The specific order is as follows:

  1. Notifies the observer that the run loop has been started.
  2. Notify the observer of any timer to be started
  3. Notifies the observer of any non-Port-based sources to be started.
  4. Start any prepared non-Port-based source
  5. If the port-based source is ready and in the waiting status, start immediately and go to step 9.
  6. Notify the observer thread to enter sleep
  7. Place the thread to sleep until any of the following events occur:
    • An event arrives at a port-based source.
    • Timer start
    • The time set by Run loop has timed out.
    • Run loop is explicitly wakened
  8. The notification observer thread will be awakened.
  9. Process unprocessed events
    • If the user-defined timer starts, process the timer event and restart the run loop. Go to step 2
    • If the input source starts, send the corresponding message
    • If the run loop is explicitly awakened and the time has not timed out, restart the run loop. Go to step 2
  10. Notifies the observer of the end of the run loop.

Because the timer and the observer of the Input Source send messages before the corresponding event occurs, there may be an error between the notification time and the actual event occurrence time. If you need precise time control, you can use sleep and wake-up notifications to help you proofread the actual event time.

When you run the run loop, the timer and other periodic events are often passed. Canceling the run loop will also terminate message transmission. A typical example is mouse path tracking. Because your code gets messages directly instead of passing messages through the program, the active timer does not start until the mouse tracking ends and gives control to the program.

Run loop can be explicitly awakened by the run loop object. Other messages can also wake up the run loop. For example, adding a new non-Port-based source will wake up the run loop so that you can immediately process the input source without waiting for other events to occur before processing.

From this event queue, we can see that:

① If an event arrives, the message will be passed to the corresponding processing program for processing. After runloop finishes processing the current event, the run loop will exit, regardless of whether the previous scheduled time has reached. You can restart the run loop to wait for the next event.

② If the thread has a source to be processed but the response event does not arrive, the thread will sleep and wait for the corresponding event to occur. This is why run loop can make the thread busy with work while it is not in sleep state.

 

2.4 When to use run loop

You only need to run a run loop explicitly when creating a secondary thread for your program. Run loop is a key part of the main thread infrastructure of the program. Therefore, the Cocoa and Carbon programs provide code to run the cycle of the main program and automatically start the run loop. The run method (or NSApplication in Mac OS X) of the UIApplication in IOS program is part of the program startup step. It starts the main loop of the program when the program starts normally. Similarly, the RunApplicationEventLoop function starts the main loop for the Carbon program. If you use the template provided by xcode to create your program, you never need to explicitly call these routines on your own.

For auxiliary threads, You need to determine whether a run loop is required. If required, configure and start it on your own. You do not need to start the run loop of a thread in any situation. For example, when you use a thread to process a pre-defined long-running task, you should avoid starting the run loop. Run loop is required only when you need more interaction with the thread, for example:

  1. Use a port or custom Input Source to communicate with other threads
  2. Use a thread Timer
  3. Use any performSelector... in Cocoa... Method
  4. Periodic thread operation

If you decide to use the run loop in the program, it is easy to configure and start. Like all Thread Programming, you need to plan the situation where the auxiliary thread exits the thread. It is often better to let the thread exit naturally than to forcibly close it.

-------- By wangzz

Reference:

Http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Multithreading/Introduction/Introduction.html#//apple_ref/doc/uid/10000057i

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.