runloop
runloop
What is?
- The system has a cyclic mechanism for managing events
runloop
Is an object that uses this loop to manage messages and events.
runloop
Whether is equal to thewhile(1) { do something ... }
?
- not
while(1)
It is a busy state that occupies resources all the time.runloop
Go to sleep when there are no messages to be processed, and wake up when messages come in that need to be processed.
runloop
The basic pattern of
- There are five in iOS
runLoop
model UIInitializationRunLoopMode
(The first one entered after bootMode
, will not be used after the startup is complete, switch tokCFRunLoopDefaultMode
)kCFRunLoopDefaultMode
(Default for AppMode
Usually the main thread is hereMode
Run)UITrackingRunLoopMode
(Interface trackingMode
forScrollView
Track the touch slide to ensure that the interface is not affected by other slidesMode
Effects)NSRunLoopCommonModes
This is a fakeMode
That is equivalent toNSDefaultRunLoopMode
andNSEventTrackingRunLoopMode
The combination of)GSEventReceiveRunLoopMode
Accept the internals of system eventsMode
, usually not.
runLoop
The basic principles of
- The main thread in the system is enabled by default
runloop
Detect events when no events need to be handledrunloop
Will be in a dormant state. - Once an event is triggered, such as a user clicking on the screen, it wakes up
runloop
Put into the listening state, and then process the event. - After the event processing is complete, it goes to sleep again and waits for the next event to wake up
runloop
Relationship to threads
runloop
One to one for threads.- Main thread creation is enabled by default
runloop
To keep the program running. - The thread of
runloop
It is lazy loading and needs to be manually enabled.
runloop
Event Handling Process
- Events trigger
runloop
Entry function ofCFRunLoopRunSpecific
Inside the function, the first notification is givenobserver
Switch the state tokCFRunLoopEntry
And then through__CFRunLoopRun
Start therunloop
Handle events __CFRunLoopRun
The core is ado - while
Loop, loop content is as follows
runloop
How was he awakened
- Hibernate threads to avoid resource hogging when there are no messages to process. Switch from user mode to kernel mode and wait for messages.
- When a message needs to be processed, the thread immediately wakes up and returns to user mode to process the message.
source0
Direct wake up via screen triggersource0
By calling themach_msg()
Function to transfer control of the current thread to the kernel/user state.
What is user mode, core mentality
- Kernel-mode: Running an operating system program. After an application process executes a system call, I/O interrupt, or clock interrupt, the process is running in the kernel
- User mode: Running a user program, indicating that the process is running in the user state
The state of the runloop
CFRunLoopObserverRef observerRef = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { switch (activity) { case kCFRunLoopEntry: NSLog (@ "runloop start"); break; Case kCFRunLoopBeforeTimers: NSLog(@" Runloop is about to handle timer events "); break; Case kCFRunLoopBeforeSources: NSLog(@" Runloop is about to handle sources "); break; Case kCFRunLoopBeforeWaiting: NSLog(@"runloop is going to sleep "); break; Case kCFRunLoopAfterWaiting: NSLog(@"runloop woke up "); break; Case kCFRunLoopExit: NSLog(@"runloop exit "); break; default: break; }}); CFRunLoopAddObserver(CFRunLoopGetCurrent(), observerRef, kCFRunLoopDefaultMode); }Copy the code
runLoop
The Caton test method
NSRunLoop
The processing time is mainly in the following two caseskCFRunLoopBeforeSources
和kCFRunLoopBeforeWaiting
betweenkCFRunLoopAfterWaiting
after
- The above two time is too long, you can judge that the main thread is stuck at this time
- You can add
Observer
To the main threadRunloop
In the listeningRunloop
Time for status change and slow listening- With a
do-while
The roadbed is cyclically treated, and the semaphore is set to determine whether the roadbed is stuck dispatch_semaphore_wait
The return valuenon-zerosaidtimeout
Caton happen- Get caton’s stack and pass it to the back end for further analysis
- With a
How do I start a resident thread
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(play) object:nil]; [thread start]; / / runloop keep alive [[NSRunLoop currentRunLoop] addPort: [NSPort port] forMode: NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; // Handle the event [self performSelector:@selector(test) onThread: Thread withObject:nil waitUntilDone:NO];Copy the code
The timer
NSTimer, CADisplayLink, dispatch_source_t
The advantages and disadvantages of
NSTimer
- The advantage is that it uses
target-action
Mode, simple and easy to use - The disadvantage is that it is easy to accidentally create circular references. Need to rely on
runloop
.runloop
If it is blocked, it will be deferred until the next timerunloop
Cycle is executed, so the time accuracy is also slightly inadequate
- The advantage is that it uses
CADisplayLink
- Advantage is high precision, each refresh after the call, suitable for non-stop redraw timing, such as video
- Disadvantages are easy to create circular references by accident.
selector
A loop interval greater than the time between redrawing each frame causes several calls to be skipped. You cannot set a single execution.
dispatch_source_t
- Based on the
GCD
, high precision, independentrunloop
Easy to use, favorite timer - Note that the timer must be held when using it, otherwise it will be released early.
- Based on the
What happens when NSTimer executes on a child thread?
NSTimer
Calls in child threads that require manual opening of child threadsrunloop
[[NSRunLoop currentRunLoop] run];
NSTimer
Why not?
If NSTimer hits trigger time while runloop is blocking, NSTimer is delayed until the next runloop cycle
NSTimer
A circular reference to?
Timer and target strongly refer to each other, resulting in circular references. This can be resolved by middleware holding Timer & Target
The GCD timer
NSTimeInterval interval = 1.0;
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), interval * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"GCD timer test");
});
dispatch_resume(_timer);
Copy the code