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#
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:
- 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.
- 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.