退出线程和计数器
想要做的事儿:停止线程或计数器的运行,或者防止再次触发。
解决方案:对于计时器,使用 NSTimer 的实例方法 invalidate。而对于线程,使用 cancel 方法。在
线程中避免使用 exit 方法,因为当调用了 exit 之后,线程就没有机会做清理工作,当你的应
用程序结束时,会发生资源泄漏。
NSThread *thread = /* Get the reference to your thread here */;
[thread cancel];
NSTimer *timer = /* Get the reference to your timer here */;
[timer invalidate];
讨论讨论:退出一个计时器非常简单;只需要简单的调用计时器的 invalidate 实例方法即可。调用
了 invalidate方法之后,计时器不会再对它的目标对象触发任何时间。
然而,线程的退出有点复杂。当线程处于休眠状态时,调用了它的 cancel 方法,线程的
循环在退出之前仍然会执行完它的全部任务。
下面我给你演示一下:
- (void) threadEntryPoint{
@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
NSLog(@"Thread Loop");
}
NSLog(@"Thread Finished");
}
}
- (void) stopThread{
NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.myThread = [[NSThread alloc]
initWithTarget:self
selector:@selector(threadEntryPoint)
object:nil]; [self performSelector:@selector(stopThread)
withObject:nil
afterDelay:3.0f];
[self.myThread start];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
这段代码创建了一个 NSThread 实例,并立即启动。我们的线程在执行它的任务之前,
每次循环都会休眠 4 秒钟。然而,在线程开始之前,我们调用了 stopThread 方法,该方法会
在 3 秒钟后执行,stopThread 方法调用了当前线程的 cancel 方法,试图让线程退出它的循
环。现在让我们允许程序,可以看到控制台窗口打印出如下信息:
...
Thread Entry Point
Cancelling the Thread
Releasing the thread
Thread Loop
Thread Finished
你可以清晰的看到,即使在循环中间 cancel 请求已经触发了,但是我们的线程在退出之
前,仍会完成当前的循环。这是一个非常普遍的陷阱,在执行任务之前,检查线程是否被
cancel 了,可以简单的避免外部影响内部线程的循环。我们通过重写上面的代码,在执行任
务前,先检查外部影响,确定线程是否被cancel了。如下代码:
- (void) threadEntryPoint{
@autoreleasepool {
NSLog(@"Thread Entry Point");
while ([[NSThread currentThread] isCancelled] == NO){
[NSThread sleepForTimeInterval:4];
if ([[NSThread currentThread] isCancelled] == NO){
NSLog(@"Thread Loop");
}
}
NSLog(@"Thread Finished");
}
}
- (void) stopThread{
NSLog(@"Cancelling the Thread");
[self.myThread cancel];
NSLog(@"Releasing the thread");
self.myThread = nil;
}
- (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.myThread = [[NSThread alloc]
initWithTarget:self
selector:@selector(threadEntryPoint)
object:nil];
[self performSelector:@selector(stopThread)
withObject:nil
afterDelay:3.0f];
[self.myThread start];
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}