RunLoop series of articles

RunLoop (2) : Data structure RunLoop (3) : event loop mechanism RunLoop (4) : RunLoop and thread RunLoop (5) : RunLoop and NSTimer iOS – AutoRelease and @Autoreleasepool: RunLoop and @Autoreleasepool

CFRunLoopRef

The underlying RunLoop object is a CFRunLoopRef structure that stores:

  • _pthread:RunLoopThere is a one-to-one correspondence with threads
  • _commonModes: Collection of NSString objects (name of Mode)
  • _commonModeItems: Stores items marked as genericSource0/Source1/Timer/Observer
  • _currentMode:RunLoopCurrent operating mode
  • _modes: StoresRunLoopAll modes (CFRunLoopModeRef) mode
// CFRunLoop.h
typedef struct __CFRunLoop * CFRunLoopRef;
// CFRunLoop.c
struct __CFRunLoop {
    pthread_t _pthread;  // Corresponding to the thread
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef_modes; . };Copy the code

CFRunLoopModeRef

  • CFRunLoopModeRefOn behalf ofRunLoopOperation mode of;
  • aRunLoopContains several modes, each of which contains several modesSource0/Source1/Timer/Observer;
  • RunLoopOnly one Mode can be selected at startup as currentMode.
  • If you need to switch Mode, you can only exit the current Loop and select another Mode to enter. Switching Mode will not cause the program to exit.
  • In different modesSource0/Source1/Timer/ObserverCan be separated from each other;
  • If there is nothing in ModeSource0/Source1/Timer/Observer.RunLoopWill quit immediately.
// CFRunLoop.h
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
// CFRunLoop.c
struct __CFRunLoopMode {
    CFStringRef _name;             // Mode type, for example, NSDefaultRunLoopMode
    CFMutableSetRef _sources0;     // CFRunLoopSourceRef
    CFMutableSetRef _sources1;     // CFRunLoopSourceRef
    CFMutableArrayRef _observers;  // CFRunLoopObserverRef
    CFMutableArrayRef _timers;     // CFRunLoopTimerRef. };Copy the code

Common modes of RunLoop

ModeName describe
NSDefaultRunLoopMode / KCFRunLoopDefaultMode The default mode
UITrackingRunLoopMode Interface tracking Mode, used for ScrollView tracking touch sliding, to ensure that the interface sliding is not affected by other modes;
NSRunLoopCommonModes / KCFRunLoopCommonModes General mode (default includes KCFRunLoopDefaultMode and UITrackingRunLoopMode)



This pattern is not an actual pattern, it is just a special flag, is synchronousSource0/Source1/Timer/ObserverTechnical solutions to multiple modes. Marked as generic modeSource0/Source1/Timer/ObserverIt’s going to be in the _commonModeItems collection, and it’s going to synchronize theseSource0/Source1/Timer/ObserverTo multiple modes.

Remark:

  • NSDefaultRunLoopModeandNSRunLoopCommonModesBelong toFoundationFramework;
  • KCFRunLoopDefaultModeandKCFRunLoopCommonModesBelong toCore FoundationFramework;
  • The former is the encapsulation of the latter, the same function.

What are the benefits of CFRunLoopModeRef? Why does Runloop have multiple modes?

  • Mode achieves the effect of masking whenRunLoopRunning under Mode1 does not handle Mode2 events;
  • Such asNSDefaultRunLoopModeDefault mode andUITrackingRunLoopModeScroll mode, when scrolling the screen will switch to scroll mode, do not have to deal with the default mode of events, ensure that UITableView and other smooth scrolling.

CFRunLoopSourceRef

  • inRunLoopThere are two very important concepts, one of which is mentioned abovemodelThere is another oneThe event source.The event sourceDivided intoInput SourcesandTimer SourcesTwo;
  • Input SourcesIs divided intoSource0andSource1Two kinds, the following__CFRunLoopSourceCommon body inunionIn theversion0andversion1They correspond separatelySource0andSource1.
// CFRunLoop.h
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
// CFRunLoop.m
struct __CFRunLoopSource {
    CFRuntimeBase _base;
    uint32_t _bits;
    pthread_mutex_t _lock;
    CFIndex _order;                       /* immutable */
    CFMutableBagRef _runLoops;
    union {
        CFRunLoopSourceContext version0;  /* immutable, except invalidation */
        CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
    } _context;
};
Copy the code

Source0 differs from Source1:

Input Sources The difference between
Source0 Need to wake up thread manually: addSource0toRunLoopDoes not actively wake up the thread, you need to wake it up manually.

① Touch event processing

2.performSelector:onThread:
Source1 Ability to wake up threads

① Communication between threads based on Port

② System event capture: System event capture is implemented bySource1To deal with it and then hand it overSource0To deal with

CFRunLoopTimerRef

  • CFRunloopTimerandNSTimerIt’s toll-free bridged, can be exchanged;
  • performSelector:withObject:afterDelay:Method createstimerTo add toRunLoopIn the.
// CFRunLoop.h
typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
// CFRunLoop.c
struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;           // Add a RunLoop for this timer
    CFMutableSetRef _rlModes;        // All modeName containing the timer
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;        /* immutable ideal time interval */    
    CFTimeInterval _tolerance;       /* mutable time bias */  
    uint64_t _fireTSR;	             /* TSR units */
    CFIndex _order;                  /* immutable */
    CFRunLoopTimerCallBack _callout; /* immutable callback port */
    CFRunLoopTimerContext _context;  /* immutable, except invalidation */
};
Copy the code

CFRunLoopObserverRef

role

  • CFRunLoopObserverRefUsed to monitorRunLoopOf the six active states
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags.CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),          // About to enter RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1),   // Timers are about to be processed
    kCFRunLoopBeforeSources = (1UL << 2),  // About to handle Sources
    kCFRunLoopBeforeWaiting = (1UL << 5),  // About to go to sleep
    kCFRunLoopAfterWaiting = (1UL << 6),   // Just woke up from hibernation
    kCFRunLoopExit = (1UL << 7),           // 即将退出 RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU  // indicates all of the above states
};
Copy the code
  • UI refresh (BeforeWaiting)
  • Autorelease Pool (BeforeWaiting)

define

// CFRunLoop.h
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
// CFRunLoop.c
struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;              // Add a RunLoop to the observer
    CFIndex _rlCount;
    CFOptionFlags _activities;	        /* immutable to monitor the activity state */
    CFIndex _order;                     /* immutable */
    CFRunLoopObserverCallBack _callout;	/* immutable callback port */
    CFRunLoopObserverContext _context;	/* immutable, except invalidation */
};
Copy the code

The _activities in CFRunLoopObserverRef is used to hold the active status of RunLoop. When the state of RunLoop changes, all observers listening for this state are notified via the _callout callback.