The Runloop of questions on iOS face

Source: Internet
Author: User
Tags gcd instance method

This paper focuses on the following parts of the Runloop narrative.

1.runloop What is the concept of/runloop?

2.Nsrunloop and Cfrunloopref?

3.runloop and thread relationships?

4.runloop external interface/runloop several classes?

5.runloop internal logic?

6.runloop application scenario?

1.runloop What is the concept of/runloop?

The Run loops is part of the thread-related infrastructure framework. A run Loop is an event-handling loop that is used to schedule work and handle input events. in fact , the inside is a do- while loop, which constantly handles various tasks within the loop (more than the Source,Timer, Observer). The purpose of using the run loop is to have your thread busy working when you have a job, It is dormant when you are not working.

2.nsrunloop and Cfrunloopref?

We can no longer manipulate the run loop object of another thread in one thread , which is likely to cause unintended consequences. Fortunately, the opaque class cfrunloopref in corefundation is thread-safe, and both types of run loops can be used in a mixed manner. the nsrunloop class in Cocoa can be done by using an instance method:

-(CFRUNLOOPREF) Getcfrunloop;

gets the corresponding cfrunloopref class, to achieve thread-safe purposes.

Cfrunloopref is within the framework of Corefoundation, which provides APIs for pure C functions, all of which are thread-safe.

Nsrunloop is a cfrunloopref-based package that provides an object-oriented API, but these APIs are not thread-safe.

3.runloop and thread relationships?

Run Loop, as its name implies, loops represent a loop that, together with Run, represents a loop that has been running. In fact, therun loop and the thread are tightly connected, so you can say that the run loop is meant for threading and without threads, it doesn't have to exist. Run loops is the infrastructure part of the thread, and both Cocoa and corefundation provide the run loop object for easy configuration and management of the thread's run Loop(This is Cocoa for example). Each thread, including the main thread of the program,has a corresponding run loop object.

the run loop of the 3.1 main thread is started by default.

IOS Application, the program starts with a following main () function:

int Main (int argc,Char *argv[])     {            @autoreleasepool {                Returnclass]));           }  }

The focus is on the uiapplicationmain () function, which sets a Nsrunloop object for the main thread , This explains why this article begins with the reason why our application can rest in the absence of an operation and respond immediately when it needs to be worked on.

3.2 to other threads, therun loop is not started by default, and if you need more thread interaction you can manually configure and start it if the thread is simply going to perform a long, determined task. 3.3 in any of the threads of a Cocoa program, you can pass:
Nsrunloop   *runloop = [Nsrunloopcurrentrunloop];

To get the run loop to the current thread .

4.runloop External interface/runloop several classes?

There are 5 classes in corefoundation about Runloop:

Cfrunloopref
Cfrunloopmoderef
Cfrunloopsourceref
Cfrunlooptimerref
Cfrunloopobserverref

The Cfrunloopmoderef class is not exposed externally, but is encapsulated by the Cfrunloopref interface. Their relationship is as follows:

A runloop consists of several mode, and each mode contains several source/timer/observer. Each time you invoke the main function of Runloop, you can specify only one mode, which is called CurrentMode. If you need to switch mode, you can only exit Loop and then reassign a mode entry. This is done mainly to separate different groups of source/timer/observer, so that they do not affect each other.

Cfrunloopsourceref is where the event occurs. There are two versions of Source: Source0 and Source1.
Source0 only contains a callback (function pointer), which does not actively trigger events. When used, you need to call cfrunloopsourcesignal (source), mark the source as pending, and then manually invoke Cfrunloopwakeup (Runloop) to wake the Runloop and let it handle the event.
Source1 contains a mach_port and a callback (function pointer) that is used to send messages to each other through the kernel and other threads. This Source can actively wake up the runloop thread, the principle of which will be mentioned below.

Cfrunlooptimerref is a time-based trigger, and Nstimer is toll-free bridged, which can be mixed. It contains a length of time and a callback (function pointer). When it joins the Runloop, Runloop registers the corresponding point in time, and when the time point is reached, the Runloop is awakened to execute that callback.

CFRUNLOOPOBSERVERREF is the Observer, each Observer contains a callback (function pointer), and when the state of RUNLOOP changes, the observer can accept the change through a callback. There are several points of time that can be observed:

typedef cf_options (Cfoptionflags, cfrunloopactivity) {kcfrunloopentry= (1UL<<0),//coming into LoopKcfrunloopbeforetimers = (1UL<<1),//The Timer is about to be processedKcfrunloopbeforesources = (1UL<<2),//The Source is about to be processedKcfrunloopbeforewaiting = (1UL<<5),//going into hibernationKcfrunloopafterwaiting = (1UL<<6),//just woke up from hibernation.Kcfrunloopexit = (1UL<<7),//about to exit loop};

The above source/timer/observer is collectively referred to as mode item, and an item can be added to multiple mode simultaneously. However, an item is not effective when it is repeatedly added to the same mode. If a mode does not have a single item, the Runloop will exit directly without entering the loop.

5.runloop internal logic?

As you can see, the runloop is actually a function that is internally a do-while loop. When you call Cfrunlooprun (), the thread stays in the loop until it expires or is stopped manually, and the function returns.

6.runloop application scenario? 6.1Autoreleasepool

After the app starts, Apple registers two Observer in the main thread Runloop, and its callback is _wraprunloopwithautoreleasepoolhandler ().

The first Observer monitored event is Entry (which is about to enter loop), and its callback calls _objc_autoreleasepoolpush () to create an auto-free pool. Its order is-2147483647, the highest priority, which guarantees that the creation of the release pool occurs before all other callbacks.

The second Observer monitored two events: beforewaiting (ready to Hibernate) call _objc_autoreleasepoolpop () and _objc_autoreleasepoolpush () to release the old pool and create a new one , exit (which is about to exit Loop) calls _objc_autoreleasepoolpop () to release the auto-free pool. This Observer order is 2147483647, with the lowest priority, ensuring that its free pool occurs after all other callbacks.

The code that executes on the main thread is usually written in a callback such as an event, or a timer callback. These callbacks are surrounded by runloop created autoreleasepool, so there is no memory leak, and developers do not have to display the Create Pool.

6.2 Timers

Nstimer In fact is cfrunlooptimerref, between them is toll-free bridged. After a nstimer is registered with Runloop, Runloop registers good events for its repeated points in time. For example 10:00, 10:10, 10:20 these several time points. Runloop to conserve resources, it does not callback the timer at a very accurate point in time. The Timer has a property called tolerance (latitude), which indicates how much maximum error is allowed when the point is reached.

If a point in time is missed, such as a long task, then the callback at that point in time skips over and does not postpone execution. Like waiting for the bus, if 10:10 I was busy playing mobile phone missed that point of the bus, then I can only wait 10:20 this trip.

The Cadisplaylink is a timer that is consistent with the screen refresh rate (but the actual implementation is more complex, and the Nstimer is not the same, the inside is actually manipulating a Source). If a long task is performed between two screen refreshes, then one frame is skipped (similar to nstimer), creating a feeling of stuttering. When sliding tableview quickly, even a single frame of the lag will make the user aware. Facebook Open source Asyncdisplaylink is to solve the problem of the interface, and its internal use of Runloop, this later I will write a separate page blog to analyze.

6.3Performselecter

When you call NSObject's performselecter:afterdelay:, it actually creates a Timer inside it and adds it to the runloop of the current thread. So if the current thread does not have Runloop, then this method will fail.

When calling Performselector:onthread:, it will actually create a Timer to add to the corresponding thread, similarly, if the corresponding thread does not runloop the method will also be invalidated.

6.4Incident response

Apple has registered a Source1 (Mach Port-based) to receive system events with a callback function of __iohideventsystemclientqueuecallback ().

When a hardware event (Touch/Lock screen/shake, etc.) occurs, a Iohidevent event is first generated by Iokit.framework and received by springboard. Springboard only receives keystrokes (lock screen/mute, etc.), touches, accelerates, approaches sensors, etc., and then forwards it to the desired app process using Mach port. Then the apple-registered SOURCE1 triggers the callback and calls _uiapplicationhandleeventqueue () to distribute the app internally.

_uiapplicationhandleeventqueue () iohidevent processed and packaged as uievent for processing or distribution, including identification uigesture/processing screen rotation/sending to UIWindow, etc. Usually events such as UIButton clicks and touchesbegin/move/end/cancel events are done in this callback.

6.5 Gesture Recognition

When the above _uiapplicationhandleeventqueue () identifies a gesture, it first calls Cancel to break the current Touchesbegin/move/end series callback. The system then marks the corresponding Uigesturerecognizer as pending.

Apple registered a Observer monitor beforewaiting (loop is about to enter hibernation) event, this Observer callback function is _uigesturerecognizerupdateobserver (), Inside it gets all the gesturerecognizer that have just been marked for processing and executes the Gesturerecognizer callback.

When there is a change in Uigesturerecognizer (Create/Destroy/state change), the callback will be processed accordingly.

6.6 Interface Update

When manipulating the UI, such as changing the Frame, updating the Uiview/calayer hierarchy, or manually invoking the Uiview/calayer Setneedslayout/setneedsdisplay method, this uiview/ The Calayer is marked for processing and is committed to a global container.

Apple has registered a Observer listener beforewaiting (going into hibernation) and exit (about to exit the loop) event, callback to execute a long function:
_ZN2CA11TRANSACTION17OBSERVER_CALLBACKEP19__CFRUNLOOPOBSERVERMPV (). This function iterates through all the pending uiview/calayer to perform the actual drawing and adjustment, and updates the UI interface.

The call stack inside this function is probably the same:

_ZN2CA11TRANSACTION17OBSERVER_CALLBACKEP19__CFRUNLOOPOBSERVERMPV ()    Quartzcore:ca::transaction::observer_ Callback:        ca::transaction::commit ();            Ca::context::commit_transaction ();                Ca::layer::layout_and_display_if_needed ();                    Ca::layer::layout_if_needed ();                        [Calayer layoutsublayers];                            [UIView layoutsubviews];                    Ca::layer::d isplay_if_needed ();                        [Calayer display];                            [UIView DrawRect];
6.7 About GCD

In fact, the bottom of the Runloop will also use GCD things. However, some of the interfaces provided by GCD also use Runloop, such as Dispatch_async ().

When Dispatch_async (Dispatch_get_main_queue (), block) is called, Libdispatch sends a message to the runloop of the main thread, the Runloop is awakened, and the block is taken from the message. and execute the block in the callback __cfrunloop_is_servicing_the_main_dispatch_queue__ (). But this logic is limited to dispatch to the main thread, and dispatch to other threads is still handled by Libdispatch.

6.8 About network Requests

In IOS, the interface for network requests has the following layers from bottom to top:

cfsocketcfnetwork        afnetworkingnsurlsession    ->afnetworking2, Alamofire

The Cfsocket is the lowest interface and is responsible for socket communication only.
Cfnetwork is an upper package based on Cfsocket and other interfaces, ASIHTTPRequest works on this layer.
Nsurlconnection is a higher-level package based on the cfnetwork, providing an object-oriented interface that afnetworking works on this layer.
Nsurlsession is a new interface in IOS7, which is ostensibly tied to nsurlconnection, but the bottom layer still uses some of the nsurlconnection features (such as Com.apple.NSURLConnectionLoader threads), AFNetworking2 and alamofire work on this layer.

The following is the main introduction of the work of the nsurlconnection process.

Usually when you use nsurlconnection, you pass in a Delegate, and when [connection start] is called, the Delegate receives an event callback. In fact, the inside of the start function gets currentrunloop, and then adds 4 Source0 (the source that needs to be triggered manually) in DefaultMode. Cfmultiplexersource is responsible for various Delegate callbacks, and Cfhttpcookiestorage is dealing with a variety of cookies.

When we start the network transfer, we can see that Nsurlconnection created two new threads: Com.apple.NSURLConnectionLoader and Com.apple.CFSocket.private. Where the cfsocket thread is handling the underlying socket connection. Nsurlconnectionloader this thread internally uses Runloop to receive the event of the underlying socket, and notifies the upper Delegate through the Source0 previously added.

The Runloop in Nsurlconnectionloader receives notifications from the underlying cfsocket through some of the Mach Port-based Source. When a notification is received, it sends a notification to SOURCE0, such as Cfmultiplexersource, at the appropriate time, and wakes the runloop of the Delegate thread to handle the notifications. Cfmultiplexersource will perform the actual callback to Delegate on the runloop of the Delegate thread.

PS: Poke here--in-depth understanding of Runloop

The Runloop of questions on iOS face

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.