The value of Runloop

    1. Let’s think about it: why can the program handle various events of the user, and can guarantee that the program does not quit? Answer: because there is a system inside the program default run loop, so can ensure that the program does not exit, and handle the user’s various events

    1. To understand why we use run loops, we can look at the purpose of using run loops. With run loops we can:
    • A. Ensure that the program does not exit;
    • B. Responsible for handling input events;
    • C. If no event occurs, the program enters the hibernation state.
  • From the above, we can conclude why we should use the running loop, because this is the basic of an APP. Without the running loop, there will be no normal operation of the APP.


    1. From the above understanding, we can summarize the advantages of running a loop: do something when there is something to do, and rest when there is nothing to do; Advantages: save CPU resources, improve program performance;

Runloop with thread

    1. Each thread has a message loop inside it. The message loop of the main thread is enabled by default, the message loop of the child thread is not enabled by default. Each running loop corresponds to a unique thread. How to keep the child thread immortal
    1. Hibernation and activation of threads during execution are managed by RunLoop objects
  • 3.RunLoop is used to manage threads
    1. Each thread has a RunLoop object. Can be obtained through specific methods
    1. However, it is important to note that although every thread can fetch a RunLoop object, not every thread has an instance object. We can understand that if we do not fetch a RunLoop, the RunLoop does not exist. When we fetch a RunLoop, if it does not exist, we will create it. In the main thread, the MainRunLoop is created and activated by default
    1. Each thread has a unique RunLoop object corresponding to it
  • 7. The key to determining whether runloop is effective is whether there are event sources or timing sources

How Runloop works

Know the Runloop

  • NSRunloop
  • CFRunLoopRef
  • NSRunloop thread is not safe, CFRunLoopRef thread is safe. NSRunLoop is a Class in the Cocoa framework, corresponding to the CFRunLoopRef class in the Core Fundation. The difference between the two is that the former is not thread-safe, while CFRunLoopRef is thread-safe. So: NSRunloop cannot call methods of other threads.
  • Differences between the two apis 2: CFRunLoopRef creates a timer that must be added to the runloop before it can be executed. When adding a timer, specify mode defaurce mode. When I do something, runloop will switch from default mode to another mode. If I do something with scrollerView, it will switch from default mode to Tracking mode. Roonloop can only execute one mode at a time.
  • NSRunLoop is a layer of OC wrapper based on CFRunLoopRef and provides object-oriented apis, but these apis are not thread-safe. Therefore, to understand the internal structure of RunLoop, it is necessary to study the API of CFRunLoopRef (Core Foundation level).

  • The RunLoop class has five classes
    • CFRunLoopRef
    • CFRunLoopModeRef / / model
    • CFRunLoopSourceRef // Event source
    • CFRunLoopTimerRef // Time source
    • CFRunLoopObserverRef // Observer

Running cycle nature

  • Literally, running a loop
  • Inside it is a do-while loop that continuously processes various tasks (such as Source, Timer, Observer)
  • The body of the loop starts by detecting if there are any events that need to be processed, processing them if there are, and sleeping to save CPU time if there are none
  • What is an input source?
  • What is a pattern?
  • What is an observer
  • Let’s think about it: why can the program handle various events of the user, and can guarantee that the program does not quit? Answer: because there is a system inside the program default run loop, so can ensure that the program does not exit, and handle the user’s various events
  • To understand why we use run loops, we can look at the purpose of using run loops. With run loops we can:

  • A. Ensure that the program does not exit;
  • B. Responsible for handling input events;
  • C. If no event occurs, the program enters the hibernation state.
  • From the above, we can conclude why we should use the running loop, because this is the basic of an APP. Without the running loop, there will be no normal operation of the APP.
  • From the above understanding, we can summarize the advantages of running a loop: do something when there is something to do, and rest when there is nothing to do; Advantages: save CPU resources, improve program performance;
  • System default is a running cycle, can ensure that the program die; The system runs loops on the main thread by default
  • Each thread has a message loop inside it. The message loop of the main thread is enabled by default, the message loop of the child thread is not enabled by default. Each running loop corresponds to a unique thread. How to keep the child thread immortal
  • Hibernation and activation of threads during execution are managed by RunLoop objects
  • RunLoop is used to manage threads
  • Each thread has a RunLoop object. Can be obtained through specific methods
  • However, it is important to note that although every thread can fetch a RunLoop object, not every thread has an instance object. We can understand that if we do not fetch a RunLoop, the RunLoop does not exist. When we fetch a RunLoop, if it does not exist, we will create it. In the main thread, the MainRunLoop is created and activated by default
  • Each thread has a unique RunLoop object corresponding to it
  • The life cycle of the running loop: created on the first fetch and destroyed at the end of the thread
  • Run one RunLoop at a time, and you specify (explicitly or implicitly) how the RunLoop will run. When a pattern is passed to RunLoop, only the Input Source corresponding to that pattern is monitored and allows RunLoop to handle events. (Similarly, only Observers corresponding to this pattern are notified.)

  • A runloop is like an event drive, waking up when there’s something to do and sleeping when there’s nothing to do

int main(int argc, char * argv[]) { 
	while (AppIsRunning) { 
		id whoWakesMe = SleepForWakingUp(); 
		id event = GetEvent(whoWakesMe); 
		HandleEvent(event); 
	} 
	return 0; 
} 

Copy the code
  • Keeps the program running and accepting user input
  • Determines which events the program should handle and when
  • Call decoupling (Message Queue)
  • Save CPU time

Runloop workflow

  • Create the message (that is, the input source);
  • Specify the mode in which the event (source) runs in the loop and add it to the loop;
  • Messages run when the event pattern matches the pattern of the message loop.
  • Summary of operation logic: Each thread has one runLoop. The main thread’s runLoop is created by default as soon as the program starts. Once created, default modes are added to it, and each mode contains multiple source /timer/observer modes. Once these modes have been added, the Observer listens for the main thread’s runloop. Once inside the runloop, it starts processing events, first timer, then source0, and then source1. After processing all these events repeatedly, if there are no events, the runloop will go to sleep. When the user triggers a new event, the runloop will wake up. After waking up the Runloop, it will go back to step 2 and process the new timer again. The new source0, the new source1, goes to sleep and goes back and forth, and when we close the program or force it out, at that point the Observer will listen on all runloop exits.

Input source (mx: message, time – things to do)

  • 1. Events that RunLoop can handle: Input source (event source), timing source;
    • Input sources are user events, such as touch events, timer events NSTimer, selector events;
    • The input source is to receive the message; When configuring runloop for a long-lived field, add at least one input source to receive messages
    • CFRunLoopSourceRef is where the event is generated

  • 2. Input source (event source)
    • 1) Generally used to handle asynchronous events;
    • 2) There are two ways to divide
      • Old: classified according to apple official documentation
      • New: Partition based on function call stack (source0 and source1)
    • 3) Old: classified according to apple official documents
      • Cocoa Perform Selector Sources
      • Custom Input Sources
      • Port-based Sources communicate with other threads through the kernel to receive and distribute system events
      1. New: Partition based on function call stack (source0 and source1)
      • Source0 is non-port-based and is manually triggered by the user, such as touch sliding, etc. Contains only one callback (function pointer), which does not actively fire events. To use this, you need to call CFRunLoopSourceSignal(source), mark the source as pending, and then manually call CFRunLoopWakeUp(runloop) to wake up the Runloop to handle the event.
      • Source1 is an event triggered by some port within the system

  • 3. The timing sources

    • 1) Generally used to handle synchronous events
    • 2) NSTimer (Add timer)
      1. CFRunLoopTimerRef is a time-based trigger
      1. CFRunLoopTimerRef basically says NSTimer, which is affected by the Mode of RunLoop
      1. The GCD timer is not affected by the RunLoop Mode
    • 6) You can add multiple Nstimers to a mode, that is, when creating nstimers, you can specify the mode in which it will run.
  • The default running cycle mode, when a triggering event occurs, the general clock will temporarily stop. This is where most of the run cycle mode takes place


[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSDefaultRunLoopMode]; 

Copy the code
  • NSRunLoopCommonModes This mode is “listen to scroll mode”, touch screen drag does not care, or continue to execute the clock

[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
	
Copy the code

  • 4. The performSelector source
      1. When calling NSObject performSelecter: afterDelay: after its internal will actually create a Timer and add to the current thread RunLoop. So if the current thread does not have a RunLoop, this method will fail.
      1. When the performSelector: onThread: when, in fact, it will create a Timer is added to the corresponding thread, in the same way, if the corresponding thread no RunLoop this method will fail.
      1. PerformSelector application: allows certain events (actions, tasks) to be executed in a particular mode; Sometimes the image is too large and rendering to the screen takes time, which can cause the interface to get stuck. You can make the image execute after the UIScrollView is finished scrolling

[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:2 inModes:@[NSDefaultRunLoopMode]]; 

Copy the code

    1. Custom source

    1. Based on port source

Mode (mx: get the source to configure a mode, is how to work mode)

  • RunLoopMode is a collection of observers: event sources, timers, and RunLoop observers for notification
  • CFRunloopModeRef indicates the running mode of Runloop
  • A Runloop can have multiple modes, a mode can have multiple Source \observer\ timers, and so on
  • Each time a runloop starts, only one mode can be specified, and this mode is called the current mode of the runloop
  • To switch mode, exit the current Runloop and specify another mode. RunLoop can only run in one mode at a time. To change modes, pause the current Loop and restart the new one.
  • This is mainly to separate the different groups of timers and so on, so that they are not affected by each other
  • Rules for using mode
      1. Only one mode exists at a time
      1. The principle for switching Mode is to stop the current Loop and restart the new Loop

Type of mode:

  • NSDefaultRunLoopMode: default state, idle state
/ / NSDefaultRunLoopMode use [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @ the selector (timerTick:) userInfo:nil repeats:YES];Copy the code
  • UITrackingRunLoopMode: sliding ScrollView

  • UIInitializationRunLoopMode: private, App is started

  • NSRunLoopCommonModes: Set of modes

// If you don't want Timer to be affected by ScrollView, Need to add to the NSRunLoopCommonModes NSTimer * timer = [NSTimer timerWithTimeInterval: 1.0 target: self selector: @ the selector (timerTick:)  userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];Copy the code

  • NS (Cocoa) beginning
    • NSDefaultRunLoopMode Default Mode (the most common loopmode) Usually The main thread runs in This mode to deal with modal panels (The mode to deal with input sources other than NSConnection objects. This is The most DefaultMode is commonly used run-loop mode. Available in iOS 2.0 and later.
    • NSEventTrackingRunLoopMode this mode for processing window, mouse events, such as component drag input source UITrackingRunLoopModes time does not handle events; TrackingRunLoopMode tracks the state of the ScrollView as it slides
    • NSRunLoopCommonModes (set of modes, Including NSDefaultRunLoopMode and UITrackingRunLoopMode (Objects added to a run loop using this value as the mode are) Monitored by all run loop modes that have been declared as a member of the set of “common” modes; See the description of CFRunLoopAddCommonMode for details.); Which modes are marked as “Common” by default: The main thread RunLoop has two preset modes: kCFRunLoopDefaultMode and UITrackingRunLoopMode. Both modes have been marked as “Common” properties. This mode is used to configure group mode. If an input source is associated with this mode, the input source is associated with all modes in the group. This is a configurable set of common patterns. Associating input Sources with this pattern also associates input Sources with other patterns in the group.
    • NSConnectionReplyMode This mode is used to process NSConnection callback events. : Processes NSConnection events. This mode is internal to the system and is rarely used by users
    • NSModalPanelRunLoopMode Modal mode in which RunLoop processes only modal-related events

  • CF start (Core Foundation)1) The system registers five modes by default
    • KCFRunLoopDefaultMode Specifies the default Mode of the App, in which the main thread usually runs. By default, all operations are included, and this mode is used in most cases, including almost all input sources (except NSConnection), corresponding to NSDefaultRunLoopMode
    • UITrackingRunLoopMode Interface tracing Mode, used by ScrollView to track touch sliding, ensuring that the interface sliding is not affected by other modes
    • UIInitializationRunLoopMode when just start the App the first to enter the first Mode, start after the completion of the will no longer be used
    • GSEventReceiveRunLoopMode accept system internal Mode of events, usually in less than
    • Kcfrunloopcommonmode This is a placeholder Mode, not a real Mode

Mode switch

  • Switch mode switch 1: NSDefaultRunLoopMode for NSEventTrackingRunLoopMode

    • When you create a Timer and add DefaultMode, the Timer gets repeated callbacks, but when you swipe a TableView, RunLoop switches mode to TrackingRunLoopMode, The Timer will not be called back and the sliding operation will not be affected.
    • When the event mode is set to NSDefaultRunLoopMode, drag the UITextView interface and the timing source stops running. When you stop dragging, the timing source continues to run. When the event mode is set to NSRunLoopCommonModes, drag the UITextView interface to continue running. In addition, when the event mode is set to NSRunLoopCommonMode, the message loop mode is kCFRunLoopDefaultMode when the UITextView interface is not dragged, and when the UITextView interface is dragged, The message loop mode automatically changes to UITrackingRunLoopMode

  • Mode switchover Example 2

    • The timer returned by the scheduledTimer call has been automatically added to the current runLoop and is NSDefaultRunLoopMode
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector: @ the selector (run) the userInfo: nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];Copy the code
  • When you slide the ScrollView, the timer will expire because the timer is added to NSDefalutRunLoopMode by default, After sliding the ScrollView, the system changes the RunLoop to UITrackingRunLoopMode, so the timer will not execute. The solution is to add the Timer to NSRunLoopCommonModes so that scrolling the ScrollView does not affect the Timer.

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 

Copy the code

  • Mode switchover Example 3
    • Another trick is that when the tableView cell asynchronously loads the picture from the network, the main thread refreshes and displays the picture after loading, then sliding the TableView will cause a lag. The usual idea is to lazily load images when tableView slides, and then display images when it stops sliding. We can do this with RunLoop.

[self.cellImageView performSelector:@sector(setImage:)withObject:downloadedImageafterDelay:0inModes:@[NSDefaultRunLoopMode]];


Copy the code
  • When NSRunLoop is NSDefaultRunLoopMode, the TableView must stop sliding. Why? Because if you’re still sliding, the mode of RunLoop should be UITrackingRunLoopMode.

Let an event have callback methods in both modes

  • Sometimes you need a Timer that gets callbacks in both modes. One way to do this is to add the Timer to both modes.
  • Another option is to add the Timer to the top RunLoop’s “commonModeItems”. “CommonModeItems” is automatically updated by RunLoop to all modes with the “Common” property
  • Method 1:
NSTimer * timer = [NSTimer timerWithTimeInterval: 2.0 target: self selector: @ the selector (run) the userInfo: nil repeats: YES];Copy the code
  • The timer only runs in NSDefaultRunLoopMode and will not work once the RunLoop enters another mode

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

Copy the code
  • The timer only runs in the UITrackingRunLoopMode and does not work once the RunLoop enters another mode

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; 

Copy the code

  • Method 2:

// 定时器会跑在标记为 common modes 的模式下 // 标记为 common modes 的模式: 

UITrackingRunLoopMode 和 NSDefaultRunLoopMode 

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Copy the code

Runloop observer

RunLoop observer introduction

  • CFRunLoopObserverRef is the observer that listens for state changes in the RunLoop
  • Observers are observers for the state of RunLoop, and CoreFunction adds RunLoop observers to threads that are observers for events, intended to handle them as they occur.
  • In addition to processing input sources, RunLoop also generates notifications about the behavior of the RunLoop. Observers run-loop Observers can receive these notifications, and use them for additional processing on threads. If RunLoop doesn’t have any sources to monitor, it will exit as soon as you start.

Observer state

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // About to enter Runloop kCFRunLoopBeforeTimers = (1UL << 1), // About to process NSTimer kCFRunLoopBeforeSources = (1UL << 2), KCFRunLoopAfterWaiting = (1UL << 6), kCFRunLoopAfterWaiting = (1UL << 6) KCFRunLoopExit = (1UL << 7), runloop kCFRunLoopAllActivities = 0x0FFFFFFFU;Copy the code
  • First parameter: CFAllocatorGetDefault, the memory used to allocate the Observer object
  • Second argument: to set the event kCFRunLoopAllActivities that the Observer is interested in
  • The third parameter: identifies whether the Observer executes on the first run loop entry or YES on each run loop entry
  • The fourth parameter: sets the priority of the Observer to 0
  • Fifth argument: The observer listens for the callback block to the event
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { switch(activity){ case kCFRunLoopEntry: NSLog(@" about to enter loop"); break; Case kCFRunLoopBeforeTimers: NSLog(@" about to handle timers"); break; Case kCFRunLoopBeforeSources: NSLog(@" about to process sources"); break; Case kCFRunLoopBeforeWaiting: NSLog(@" about to go to sleep "); break; Case kCFRunLoopAfterWaiting: NSLog(@" just woke up from sleep "); break; Case kCFRunLoopExit: NSLog(@" about to exit loop"); break; default: break; }});Copy the code

Argument parsing


CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode); 

Copy the code
  • First parameter: which RunLoop to add a listener to
  • Second argument: The Observer object to add
  • Third parameter: in which mode to listen

Release observer


CFRelease(observer); 

Copy the code

Adding an observer

  • 1) Create an observer
// Create a runloop listener CFRunLoopObserverRef Observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities,YES, 0, ^(CFRunLoopObserverRef Observer, CFRunLoopActivity activity) {NSLog(@ "listen for RunLoop status change -- %zd",activity); });Copy the code
  • 2) Add the created observer
CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer,kCFRunLoopDefaultMode); // Add observer: listen for the status of RunLoopCopy the code
  • 3) Release the created observer
CFRelease(observer); / / releaseCopy the code

Runloop can be started in three ways:

    1. —- Unconditional access to Runloop is the easiest way, but it’s also the least recommended. Because this keeps your thread in a permanent loop, you have very little control over the Runloop itself. You can add or remove input sources and timers, but the only way to exit Runloop is to kill it. There is no way to make the Runloop run in custom mode.

[[NSRunLoop currentRunLoop] run]; 

Copy the code
    1. Set timeout —- Instead of entering Runloop unconditionally, a better approach is to run the Runloop with a preset timeout, so that the Runloop runs until an event arrives or the specified time expires. If an event arrives, the message is passed to the appropriate handler for processing, and the Runloop exits. You can restart Runloop to wait for the next event. If the specified time is up, you can simply restart Runloop or use the time to do any other work. It’s over in 2 seconds

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; 

Copy the code
    1. Specific modes —- In addition to the timeout mechanism, you can also use specific modes to run your Runloop. Modes and timeouts are not mutually exclusive and can be used at the same time when starting RunLoop. Patterns restrict the types of input sources that can pass events to Runloop. When date is set to NSDate distantFuture, never exit the process that is currently processing the suspended process until processing the other input source ends

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

Copy the code

Three ways to end:

  • Set a timeout for RunLoop
  • Tell RunLoop to stop —- The first method is recommended if it can be configured. Specifying a timeout allows the RunLoop to complete all normal operations, including sending messages to RunLoop observers, before exiting.
  • Explicitly stopping the RunLoop using CFRunLoopStop produces similar results as using a timeout. RunLoop sends all remaining notifications before exiting. Unlike setting timeouts, you can use this technique in runloops that start unconditionally.

  • Run a loop to remove the input source
    • When an input source is registered with a RunLoop, there are methods to remove it. The timer has no remove, but its invalidate method removes it from the RunLoop. Invalidate is the important and only method that removes the timer from the RunLoop, so if you create a timer, make sure you call the invalidate method when it is no longer applicable.

  • Automatic release pool, when to create and release?
    • (1) First create: create the corresponding state when runloop enters = KCFRunLoopEntry
    • (2) The last exit is the corresponding state when the runloop exits = KCFRunLoopExit
    • (3) Other creation and release
    • Every time you sleep it will automatically release the pre-release pool and create a new one
    • When you are about to go to sleep, release the automatic release pool you created last time, and then create a new release pool

Examples of runloop use

Runloop Solves the problem of stopping the cell slide timer

  • This can be resolved by adding the timer to NSRunLoopCommonModes (kCFRunLoopCommonModes)
  • Add timer to NSDefaultRunLoopMode
[NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @ the selector (timerTick:) the userInfo: nil repeats: YES]; / / and then added to the NSRunLoopCommonModes NSTimer * timer = [NSTimer timerWithTimeInterval: 1.0 target: the self selector:@selector(timerTick:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];Copy the code

Runloop brought Crash’s app back to life

  • Restart the RunLoop manually after receiving the Signal from Crash
CFRunLoopRef runLoop = CFRunLoopGetCurrent(); NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop)); While (1) {for (NSString *mode in allModes) {CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); }}Copy the code

Runloop makes the TableView lazily load images

  • We used to load in cellForIndexPaThrow, but here’s the idea
UIImage *downloadedImage = ... ; [self.avatarImageView performSelector:@selector(setImage:) withObject:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];Copy the code

  • SetupJJPerformselecterOne tableview lazy loading pictures
- (void)setupJJPerformselecterOne { NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(taskOne)  object:nil]; [thread start]; } -(void)taskOne { [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; // until 1 second later NSLog(@"taskOne is running"); }Copy the code

Runloop Periodic task of the sub-thread

  • // Execute only four times once every second

@property(nonatomic,strong)NSTimer *timer; 

- (void)handleSomeTimers:(float)startTime interval:(float)interval 
{ 
    dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
        self.timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:startTime] 
        interval:interval 
        target:self 
        selector:@selector(runTimerWithRepeatCount) 
        userInfo:nil 
        repeats:YES]; 

        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; 
        [[NSRunLoop currentRunLoop] run]; 
    }); 
} 

- (void)runTimerWithRepeatCount{
    count ++; 
    if (count == 4) { 
        [self.timer invalidate]; 
    } 
    NSLog(@"runTimer__on thread %@",[NSThread currentThread]); 
}

Copy the code

Runloop implements child thread resident

  • Runloop Runloop Application Scenario [Important] [Working with NSTimer] [Child thread resident] (Background resident runs the runTimer method; Execute method every 0.1 seconds;)
  • The purpose of child thread resident is, after the app starts, there is a thread behind the resident, you can let this thread to deal with things periodically
  • SetupJJTimerRunLoop child thread: Run the runTimer method permanently in the background; Execute the method every 0.01 seconds;
@property(nonatomic,strong)NSTimer *timer; - (void)setupJJTimerRunLoop { dispatch_async(dispatch_get_global_queue(0, 0), ^ {NSTimer * timer = [[NSTimer alloc] initWithFireDate: [NSDate dateWithTimeIntervalSinceNow: 0.01] interval: 0.01 target:self selector:@selector(runTimer) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; }); } - (void)runTimer { NSLog(@"runTimer__on thread %@",[NSThread currentThread]); }Copy the code

Runloop is used in AFN

  • AFN creates a thread and adds the thread to the runloop. The runloop listens on port and triggers the operation.
  • This is a good way to create a resident service thread
+ (void)networkRequestThreadEntryPoint:(id)__unused object { @autoreleasepool { [[NSThread currentThread] setName:@"AFNetworking"]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; // start loop, listen on port, trigger operation [runLoop run]; } } + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; // Create a thread static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread; }Copy the code