runloop

runloopWhat is?

  • The system has a cyclic mechanism for managing events
  • runloopIs an object that uses this loop to manage messages and events.

runloopWhether is equal to thewhile(1) { do something ... }

  • not
  • while(1)It is a busy state that occupies resources all the time.
  • runloopGo to sleep when there are no messages to be processed, and wake up when messages come in that need to be processed.

runloopThe basic pattern of

  • There are five in iOSrunLoopmodel
  • UIInitializationRunLoopMode(The first one entered after bootMode, will not be used after the startup is complete, switch tokCFRunLoopDefaultMode)
  • kCFRunLoopDefaultMode(Default for AppModeUsually the main thread is hereModeRun)
  • UITrackingRunLoopMode(Interface trackingModeforScrollViewTrack the touch slide to ensure that the interface is not affected by other slidesModeEffects)
  • NSRunLoopCommonModesThis is a fakeModeThat is equivalent toNSDefaultRunLoopModeandNSEventTrackingRunLoopModeThe combination of)
  • GSEventReceiveRunLoopModeAccept the internals of system eventsMode, usually not.

runLoopThe basic principles of

  • The main thread in the system is enabled by defaultrunloopDetect events when no events need to be handledrunloopWill be in a dormant state.
  • Once an event is triggered, such as a user clicking on the screen, it wakes uprunloopPut 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

runloopRelationship to threads

  • runloopOne to one for threads.
  • Main thread creation is enabled by defaultrunloopTo keep the program running.
  • The thread ofrunloopIt is lazy loading and needs to be manually enabled.

runloopEvent Handling Process

  • Events triggerrunloopEntry function ofCFRunLoopRunSpecificInside the function, the first notification is givenobserverSwitch the state tokCFRunLoopEntryAnd then through__CFRunLoopRunStart therunloopHandle events
  • __CFRunLoopRunThe core is ado - whileLoop, loop content is as follows

runloopHow 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.
  • source0Direct wake up via screen trigger
  • source0By 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

runLoopThe Caton test method

  • NSRunLoopThe processing time is mainly in the following two cases
    • kCFRunLoopBeforeSourceskCFRunLoopBeforeWaitingbetween
    • kCFRunLoopAfterWaitingafter
  • The above two time is too long, you can judge that the main thread is stuck at this time
  • You can addObserverTo the main threadRunloopIn the listeningRunloopTime for status change and slow listening
    • With ado-whileThe roadbed is cyclically treated, and the semaphore is set to determine whether the roadbed is stuck
    • dispatch_semaphore_waitThe return valuenon-zerosaidtimeoutCaton happen
    • Get caton’s stack and pass it to the back end for further analysis

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_tThe advantages and disadvantages of

  • NSTimer
    • The advantage is that it usestarget-actionMode, simple and easy to use
    • The disadvantage is that it is easy to accidentally create circular references. Need to rely onrunloop.runloopIf it is blocked, it will be deferred until the next timerunloopCycle is executed, so the time accuracy is also slightly inadequate
  • 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.selectorA 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 theGCD, high precision, independentrunloopEasy to use, favorite timer
    • Note that the timer must be held when using it, otherwise it will be released early.

What happens when NSTimer executes on a child thread?

  • NSTimerCalls in child threads that require manual opening of child threadsrunloop
  • [[NSRunLoop currentRunLoop] run];

NSTimerWhy not?

If NSTimer hits trigger time while runloop is blocking, NSTimer is delayed until the next runloop cycle

NSTimerA 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