IOS development, ios development

Source: Internet
Author: User

IOS development, ios development
Concept of RunLoop

A run loop is a loop of event processing. It is used to schedule tasks and process events continuously.

Function

  • Keep programs running continuously
  • Monitors various events in the App (touch events, Timer events, selector events)
  • CPU resources are saved and program performance is improved: When you do things, you need to take a rest.
  • One RunLoop is used to draw all the points on the screen.
Entry Function
int main(int argc, char * argv[]) {   @autoreleasepool {       return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));   }
}

UIApplicationMain () This function starts a RunLoop internally, so this function has not been returned and keeps the program running continuously. By default, this RunLoop started is related to the main thread.

RunLoop object

  • Under the Foundation framework: nsunloop (the CFRunLoopRef-based encapsulation provides object-oriented APIs, but these APIs are NOT thread-safe)
  • Core Foundation framework: CFRunLoopRef (pure C function APIs, all of which are thread-safe)

RunLoop and thread

  • Each thread has a unique RunLoop object.
  • The main thread's RunLoop has been automatically created, and the Child thread's RunLoop needs to be manually created
  • RunLoop is created when it is obtained for the first time and destroyed when the thread ends.
Nsunloop * currentRunloop = [nsunloop currentRunLoop]; // The RunLoop [nsunloop mainRunLoop] corresponding to the main thread; // The RunLoop currentRunloop corresponding to the current thread. getCFRunLoop; // convert to CFRunLoop CFRunLoopGetMain (); CFRunLoopGetCurrent (); // start a subthread [[[NSThread alloc] initWithTarget: self selector: @ selector (run) object: nil] start];-(void) run {// create the RunLoop corresponding to the sub-thread, and [nsunloop currentRunLoop];}

The following is the official Apple source code. Through analyzing the source code, we can see that pthread is used as the key in the global dictionary, and the corresponding RunLoop is created as the Value. RunLoop is created when we obtain it, if this parameter is not obtained, the main thread's RunLoop is automatically created at the beginning. There is a one-to-one correspondence between threads and RunLoop.

CFRunLoopRef CFRunLoopGetMain (void) {CHECK_FOR_FORK (); static CFRunLoopRef _ main = NULL; // no retain needed if (! _ Main) _ main = _ CFRunLoopGet0 (pthread_main_thread_np (); // no CAS needed return _ main;} CFRunLoopRef CFRunLoopGetCurrent (void) {CHECK_FOR_FORK (); CFRunLoopRef rl = (CFRunLoopRef) _ CFGetTSD (_ CFTSDKeyRunLoop); if (rl) return rl; return _ CFRunLoopGet0 (pthread_self ();} // global Dictionary, the key is pthread_t, and the value is CFRunLoopRefstatic CFMutableDictionaryRef _ CFRunLoops = NULL; // The lock static CF when accessing the Dictionary Lock_t loopsLock = CFLockInit; // obtain the RunLoopCF_EXPORT CFRunLoopRef _ timeout (pthread_t t) corresponding to a pthread {// if the input thread is 0 if (pthread_equal (t, kNilPthreadT )) {// The current thread is equal to the main thread t = pthread_main_thread_np () ;}// lock _ CFLock (& loopsLock) for the Operation; // if the current RunLoop is empty, create it. If (! _ CFRunLoops) {_ CFUnlock (& loopsLock); // create a dictionary CFMutableDictionaryRef dict = CFDictionaryCreateMutable (kCFAllocatorSystemDefault, 0, NULL, & unlock ); // create the main thread CFRunLoopRef mainLoop = _ handler (pthread_main_thread_np (); // Save the main thread CFDictionarySetValue (dict, pthreadPointer (pthread_main_thread_np (), mainLoop); if (! OSAtomicCompareAndSwapPtrBarrier (NULL, dict, (void * volatile *) & __ CFRunLoops) {CFRelease (dict);} CFRelease (mainLoop); _ CFLock (& loopsLock );} // obtain the current thread's RunLoop CFRunLoopRef loop = (CFRunLoopRef) CFDictionaryGetValue (_ CFRunLoops, pthreadPointer (t) from the dictionary; _ CFUnlock (& loopsLock); if (! Loop) {// if the current thread's runloop does not exist, create a corresponding runloop CFRunLoopRef newLoop = _ CFRunLoopCreate (t); _ CFLock (& loopsLock) for the thread ); loop = (CFRunLoopRef) CFDictionaryGetValue (_ CFRunLoops, pthreadPointer (t); // Save the current Child thread and the corresponding runloop to the dictionary if (! Loop) {CFDictionarySetValue (_ CFRunLoops, pthreadPointer (t), newLoop); loop = newLoop;} // don't release run loops inside the loopsLock, because custom may end up taking it _ CFUnlock (& loopsLock); CFRelease (newLoop);} if (pthread_equal (t, pthread_self () {_ CFSetTSD (_ CFTSDKeyRunLoop, (void *) loop, NULL); if (0 = _ CFGetTSD (_ CFTSDKeyRunLoopCntr) {_ CFSetTSD (_ CFTSDKeyRunLoopCntr, (void *) (PTHREAD_DESTRUCTOR_ITERATIONS-1 ), (void (*) (void *) _ CFFinalizeRunLoop) ;}} return loop ;}
RunLoop-related classes

Five RunLoop classes in Core Foundation

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef (time-based trigger)
  • CFRunLoopObserverRef

Note: A RunLoop contains several modes, each of which contains several sources, Timer, and Observer. Each time a RunLoop is started, only one Mode can be specified. This Mode is called CurrentMode, if you need to switch the Mode, you can only exit the Loop and re-specify a Mode to enter. In this way, you should separate the Source, Timer, and Observer of different groups so that they do not affect each other.

1. CFRunLoopSourceRef: Event source (Input Source)

-Source0: Non-Port-based (User-triggered event)

-Source1: Port-based (Message events in the System)

(Port is a method of Inter-thread communication. If two threads want to communicate, they can communicate through Port .)

 

2. CFRunLoopTimerRef

Based on the time trigger, when it is added to the RunLoop, The RunLoop registers the corresponding time point. When the time point is reached, the RunLoop will be awakened to the callback in the execution.

 

3. CFRunLoopObserverRef

The observer can monitor the status change of the RunLoop.

/* Run Loop Observer Activities */typedef CF_OPTIONS (CFOptionFlags, CFRunLoopActivity) {kCFRunLoopEntry = (1UL <0), // It is about to enter runtime = (1UL <1 ), // logs to be processed = (1UL <2), // logs to be processed SourcekCFRunLoopBeforeWaiting = (1UL <5), // logs to sleep into kCFRunLoopAfterWaiting = (1UL <6 ), // just woke up from sleep kCFRunLoopExit = (1UL <7), // will quit LoopkCFRunLoopAllActivities = 0x0FFFFFFFU };

 

-(Void) addObserver {/* parameter 1: how to allocate a bucket parameter 2: The status to be monitored kCFRunLoopAllActivities all status parameter 3: whether to listen continuously parameter 4: priority, always pass 0 parameter 5: callback when the status changes */CFRunLoopObserverRef observer = callback (CFAllocatorGetDefault (), callback, YES, 0, ^ (CFRunLoopObserverRef observer, CFRunLoopActivity activity) {switch (activity) {case kCFRunLoopEntry: NSLog (@ "coming soon"); break; case kCFRunLoopBeforeTimers: NSLog (@ "Coming Soon timer event"); break; case kCFRunLoopBeforeSources: NSLog (@ "Sources events to be processed"); break; case kCFRunLoopBeforeWaiting: NSLog (@ "coming to sleep"); break; case kCFRunLoopAfterWaiting: NSLog (@ "awakened "); break; case kCFRunLoopExit: NSLog (@ "runloop exited"); break; default: break ;}}); // Add listener to runloop/* parameter 1: runloop parameter 2: observer parameter 3: Running Mode */CFRunLoopAddObserver (CFRunLoopGetCurrent (), observer, kcfrunloopdefamode );}

 

4. CFRunLoopModeRef:RunLoop Running Mode

There are multiple running Modes in RunLoop, but RunLoop can only be run in one Mode. There must be at least Timer or Source in the Mode.

Five modes are registered by default:

  • KCFRunLoopDefaultMode: the default Mode of the App. Generally, the main thread runs in this Mode.
  • UITrackingRunLoopMode: interface tracking Mode, used for ScrollView tracking touch sliding, ensure that the interface sliding is not affected by other modes
  • UIInitializationRunLoopMode: The first Mode entered when the App is started.
  • GCEventReceiveRunLoopMode: Internal Mode for accepting system events, which is usually unavailable
  • Nsunloopcommonmodes: This is a placeholder Mode, not a real Mode
RunLoop problems and explanations 

1. Timer and sliding controls

Problem: the timer does not work when the sliding control is constantly being dragged.

Incorrect answer: runloop priority

Analysis: several common runloop modes: Default DefaultMode, UITrackingMode, and CommonModes placeholder mode. When runloop enters one mode, events in the other mode are not processed, when the Timer is in DefaultMode during running, when you drag the sliding control, runloop will immediately process the UI event and switch to UITrackingRunLoopMode. At this time, the Timer in DefaultMode will not work.

Solution: place the Timer in the hold mode of the nsunloopcommonmodes

-(Void) viewDidLoad {[super viewDidLoad]; // 1. create a timer NSTimer * timer = [NSTimer timerWithTimeInterval: 2.0 target: self selector: @ selector (run) userInfo: nil repeats: YES]; // 2. add Timer to RunLoop // [[[nsunloop currentRunLoop] addTimer: timer forMode: NSDefaultRunLoopMode]; // [[nsunloop currentRunLoop] addTimer: timer forMode: Timer]; [[nsunloop currentRunLoop] addTimer: timer forMode: nsunloopcommonmodes];}-(void) run {NSLog (@ "-------- % @", [NSThread currentThread]);}
View Code

 

Q: During multi-threaded development, time-consuming operations are generally executed in sub-threads. What are the characteristics of such threads?

Example: If a time-consuming operation is executed in the run method of the timer above, the main thread will be stuck and the sliding control will be not smooth. How can this problem be solved?

Analysis: The RunLoop loop is not enabled in the Child thread by default, so the child thread will be recycled after the task is executed.

-(Void) viewDidLoad {[super viewDidLoad]; dispatch_async (dispatch_get_global_queue (0, 0), ^ {// 1. create a timer NSTimer * timer = [NSTimer timerWithTimeInterval: 2.0 target: self selector: @ selector (run) userInfo: nil repeats: YES]; // 2. add Timer to RunLoop [[[nsunloop currentRunLoop] addTimer: timer forMode: nsunloopcommonmodes]; // 3. run RunLoop [[[nsunloop currentRunLoop] run]; // an endless loop, the subsequent code will not execute NSLog (@ "++") ;};}- (void) run {// time-consuming operation [NSThread sleepForTimeInterval: 1.0]; NSLog (@ "-------- % @", [NSThread currentThread]);}
View Code

Or:

-(Void) viewDidLoad {[super viewDidLoad]; [NSThread detachNewThreadSelector: @ selector (time2) toTarget: self withObject: nil];}-(void) time2 {// create the RunLoop nsunloop * currentLoop of the current thread = [nsunloop currentRunLoop]; // This method is automatically added to the RunLoop internally, and the running mode is the default mode [nst1_scheduledtimerwithtimeinterval: 2.0 target: self selector: @ selector (run) userInfo: nil repeats: YES]; // enable RunLoop [currentLoop run];}-(void) run {// time-consuming operation [NSThread sleepForTimeInterval: 1.0]; NSLog (@ "run ----- % @ ---- % @", [NSThread currentThread], [nsunloop currentRunLoop]. currentMode );}
View Code

 

 

This blog post will continue to improve and update the knowledge about runloop. If you have an incorrect understanding or an application instance involving runloop, please leave a message.

Reference: http://blog.ibireme.com/2015/05/18/runloop/

Related Article

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.