iOS Runloop 線程?;罴翱?/h1>
Thread *th = [[Thread alloc] initWithTarget:self selector:@selector(testThread) object:nil];
[th start];
- (void)testThread{
NSLog(@"test thread");
}
@implementation Thread
-(void)dealloc{
NSLog(@"NSThread dealoc");
}
@end
Thread *th = [[Thread alloc] initWithTarget:self selector:@selector(testThread) object:nil];
[th start];
- (void)testThread{
NSLog(@"test thread");
}
@implementation Thread
-(void)dealloc{
NSLog(@"NSThread dealoc");
}
@end
上面的代碼, Thread 這個類繼承自 NSThread ,然后重寫了 dealloc 方法,目的是為了看一下這個類是否在執(zhí)行完任務(wù)后被釋放,我們看下打印。
2020-02-19 16:05:51.150818+0800 blogTest[7713:410122] test thread
2020-02-19 16:05:51.151482+0800 blogTest[7713:410122] NSThread dealoc
從打印結(jié)果可以看出,我們的 thread 在執(zhí)行完testThread 方法之后就 dealloc 了,那我們現(xiàn)在要做的就是讓這個線程?;睿蛔屗?dealloc。
我們的目的是讓這個線程,有事做的時候活躍起來,沒有事做的時候就休眠
- (void)testThread{
NSLog(@"test thread");
// 向runloop里面添加事件source/timer/observer
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
我們將代碼改成這樣之后,發(fā)現(xiàn)沒有調(diào)用 dealloc,也就是說我們達到了?;畹男Ч?,當(dāng)我們這個線程在執(zhí)行完啊這個方法的時候就開始?;钚菝咚X了。
那我們測試下,這個線程是否一直?;睢?/p>
- (void)testThread{
NSLog(@"test thread");
// 向runloop里面添加事件source/timer/observer
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
- (void)testAnother{
NSLog(@"test another");
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self performSelector:@selector(testAnother) onThread:_thread withObject:nil waitUntilDone:NO];
}
上面的代碼意思就是,當(dāng)我們點擊屏幕的時候,就在這個子線程里面去執(zhí)行任務(wù),我們測試一下發(fā)現(xiàn),每次都會打印
2020-02-19 16:22:25.217538+0800 blogTest[7806:425090] test thread
2020-02-19 16:22:26.498719+0800 blogTest[7806:425090] test another
2020-02-19 16:22:26.825388+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.056183+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.247697+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.439158+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.598440+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.757769+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.901013+0800 blogTest[7806:425090] test another
當(dāng)我們將 ?;畹拇a去掉試一下,發(fā)現(xiàn)就會打印一下,說明線程在執(zhí)行完任務(wù)之后就死掉了。
所以當(dāng)我們想在一個線程里面多次執(zhí)行任務(wù),還不想一直創(chuàng)建和銷毀線程的時候,就可以選擇線程?;畹乃枷?,將這個線程一直?;罟┪覀兪褂谩?/p>
銷毀線程
上面的線程其實是一直在 run,雖然沒有事情做,但是是一直存在的,沒有銷毀。我們需要改下代碼
- (void)stop{
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)stopRunloop{
[self performSelector:@selector(stop) onThread:_thread withObject:nil waitUntilDone:NO];
}
當(dāng)我們需要停止到我們的runloop的時候,就手動調(diào)用 stopRunloop 方法就可以,這個方法會在當(dāng)前這個?;罹€程去調(diào)用stop方法,我們的stop方法的意思是停止掉當(dāng)前線程,這樣就做到了我們的需求。
坑
其實上面是停止不了的,run 方法,內(nèi)部會一直不斷的調(diào)用 [[NSRunLoop currentRunLoop] runMode:<#(nonnull NSRunLoopMode)#> beforeDate:<#(nonnull NSDate *)#>]; 這個方法啊,就好比,
while (1) {
[[NSRunLoop currentRunLoop] runMode:<#(nonnull NSRunLoopMode)#> beforeDate:<#(nonnull NSDate *)#>];
}
這樣,我們只是停止了一次runmode,而 run方法內(nèi)部其實會一直不斷的執(zhí)行,所以需要我們修改下代碼
- (void)stop{
_stop = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)stopRunloop{
[self performSelector:@selector(stop) onThread:_thread withObject:nil waitUntilDone:NO];
}
- (void)testThread{
NSLog(@"test thread");
// 向runloop里面添加事件source/timer/observer
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
while (!_stop) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
我們?;畹拇a,通過一個變量來控制,當(dāng)我們需要停止的時候,就不會再繼續(xù)run了,嚴(yán)謹(jǐn)點的話我們還需要在用到 ——thread 的前面都要加上判斷,判斷_thread還是否存在,在stop的時候要講_thread給置為nil,然后while的時候要判斷weakself是否存在。