To listen for the status of a RunLoop, you get nothing observer-relevant from NSRunLoop, let alone listening. CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef CFRunLoopRef Wake it up to handle these tasks, not examples here 😘)

Click on CFRunLoopRef to the API to find the related declaration CFRunLoopObserverRef that defines the Observer, which is exactly what we want 😘:

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoopSource * CFRunLoopSourceRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoopObserver * CFRunLoopObserverRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;

Copy the code

After finding the CFRunLoopObserverRef, it is time to create an Observer by finding the following function declaration in the API:

CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context);
Copy the code

This is exactly the way we want to create an OBserver 😘, take a look at the parameters it takes:

  • CFAllocatorRef allocator this mouse function explains a bunch of things on the right side of Xcode.

  • CFOptionFlags Activities means to listen for the changing state of the RunLoop (kCFRunLoopAfterWaiting, etc.)

  • Boolean repeats// indicates whether the listen is repeated

  • CFIndex order can be passed 0 for the time being

  • CFRunLoopObserverCallBack callout said listen callback method (C)

  • CFRunLoopObserverContext * Context indicates the context environment, which is used to transfer values between C methods and OC

So now to create a CFRunLoopObserverContext, also found in the API a CFRunLoopObserverContext statement

typedef struct { CFIndex version; Void * info; Const void *(*retain)(const void *info); const void *(retain)(const void *info); // reference void (*release)(const void *info); CFStringRef (*copyDescription)(const void *info); } CFRunLoopObserverContext;Copy the code

Now create a CFRunLoopObserverContext

CFRunLoopObserverContext Context = {0, (__bridge void *)(self),//OC object passed &cfretain, &cfrelease, NULL};Copy the code

Click on the above CFRunLoopObserverCallBack is API to such a declaration, which tells us monitor the parameters of the callback method how to define

typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);

Copy the code

Next, create a new C language for the callback method

static void runLoopOserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, Void *info){//void *info is what we want to pass to OC, this side can be converted to OC, we passed in self}Copy the code

Here everything is ready 😘 you can create an Observer

// Create a listener static CFRunLoopObserverRef Observer; observer = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &runLoopOserverCallBack,&context); // Register to listen on CFRunLoopAddObserver(runLoopRef, Observer, kCFRunLoopCommonModes); / / destroyed CFRelease (observer);Copy the code

End here 😘, the complete code is as follows:

To keep the RunLoop working, there’s an NSTimer here, but it doesn’t do anything, just to keep the RunLoop working, right

@interface ViewController ()

@property (nonatomic, strong)NSTimer *runLoopObServerTimer;
@property (nonatomic, copy)NSString
 *name;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self addRunLoopObserver];
    [self initData];
}

- (void)initData{
    _name = @"piaojin"; / / the default will be added to the current runLoop go, don't do anything, in order to let the runLoop has been processing tasks instead of sleep _runLoopObServerTimer = [NSTimer scheduledTimerWithTimeInterval: 0.001 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES]; } - (void)addRunLoopObserver{// Get the current CFRunLoopRef CFRunLoopRef runLoopRef = CFRunLoopGetCurrent(); CFRunLoopObserverContext Context = {0, (__bridge void *)(self), &cfretain, &cfrelease, NULL }; // Create a listener static CFRunLoopObserverRef Observer; observer = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &runLoopOserverCallBack,&context); // Register to listen on CFRunLoopAddObserver(runLoopRef, Observer, kCFRunLoopCommonModes); / / destroyed CFRelease (observer); } static void runLoopOserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){ ViewController *viewController = (__bridge ViewController *)(info); //void *info is the self(ViewController) NSLog(@) that we passed earlier"runLoopOserverCallBack -> name = %@",viewController.name); } - (void)timerMethod{// do nothing to keep the runLoop working on the task without sleeping} @endCopy the code

At this point, the current RunLoop will be listened to and the runLoopOserverCallBack callback method will be called as soon as it goes to sleep