今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

The issue of NSTimer not working in iOS

The Issue of NSTimer Not Running in iOS#

Background#

After this version was launched, it was suddenly found that the buried point data dropped sharply. After debugging, it was discovered that the method for uploading data with the timer was not being executed, but the timer method had not been modified in this version. The code is as follows:


- (BOOL)initTimer() {
        self.uploadTimer = [NSTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES];
		[[NSRunLoop currentRunLoop] addTimer:self.uploadTimer forMode:NSRunLoopCommonModes];
}

Investigation#

The handleUpload method would not execute at all, but it worked fine in previous versions. After investigation, it was found that an additional layer of asynchrony was added to the outer calling place. The calling place changed to:


dispatch_async(dispatch_get_global_queue(0, 0), ^{
    initTimer()
});

This caused the timer not to start.

Reason#

iOS uses runloop as the message loop mechanism. The main thread starts the runloop by default, but the child thread does not have a default runloop. Therefore, starting a timer in a child thread is ineffective.

Solution: Start the runloop in the child thread.


- (BOOL)initTimer() {
        self.uploadTimer = [NSTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(handleUpload) userInfo:nil repeats:YES];
		[[NSRunLoop currentRunLoop] addTimer:self.uploadTimer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop] run];
}

Reflection#

From this issue, there are two takeaways:

  1. Timers are frequently used in iOS development, and many blogs highlight various points of caution regarding timers, usually related to memory management and timer startup. However, in development, if one has not truly encountered a problem, the awareness of potential issues may not be sufficient. After this experience, I believe I will be much more attentive when using timers asynchronously in the future.
  2. In this case, initTimer is actually a class for SDK initialization. The SDK itself was not modified, but the outer application using the SDK made changes, which caused the SDK to malfunction. Therefore, when encapsulating an SDK, it is important to ensure that if a timer is used, either thread checks are performed or the code is made safe; because one cannot guarantee the conditions under which third-party callers will use it, ensuring the correctness of one's own code is essential.

References#

Operations with iOS Timers and Various Pitfalls of NSTimer

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.