iOS 如何保持线程一直在运转(二)

时间:2020-12-03 23:42:00

一、接着上一篇通过NSThread可以方便的创建一个线程,并且启动线程的Runloop,在线程体中执行一个while循环

  然后我们就可以方便得利用这个线程了

- (void)threadRun:(NSThread *)thread
{
    NSLog(@"Thread run");
    NSLog(@"hello 1");
    while (!_isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
    {
        NSLog(@"hello 2");
        _isCancelled = [currentThread isCancelled];
    }
    NSLog(@"hello 3");
}

 

二、那我们应该如何正确结束一个NSThread呢

  NSThread结束可以调用两个方法,一个是对象方法-[Thread cancel],这个方法标记NSThraed的属性isCanceled为YES,那么通过配合上面的循环,线程体本身就结束了。

                  另外一个方法是+[Thread exit],注意这个方法需要在NSThraed为当前线程中调用,该方法比较暴力不管线程中的任务是否还在执行,

                                  直接结束,也不管runloop,因此可能带来内存泄露。

 

三、NSRunloop

  - (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;

  根据官方文档,上面的API在Runloop中没有事件源或者timer的时候,该方法会立即返回NO,所以在执行这个线程体的循环时候,需要先加入一个timer

  保证while循环不会结束,也就保证了线程不会结束

- (void)threadRun:(NSThread *)thread
{
    NSLog(@"Thread run");

    
    _liveTimer = [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
                                     target:self
                                   selector:@selector(ignore:)
                                   userInfo:nil
                                    repeats:YES];
     
    
    NSThread *currentThread = [NSThread currentThread];
    NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
    
    _isCancelled = [currentThread isCancelled];

    NSLog(@"hello 1");
    while (!_isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
    {
        NSLog(@"hello 2");
        _isCancelled = [currentThread isCancelled];
        NSLog(@"hello 4");
    }
    NSLog(@"hello 3");

}

   上面的含义另外一层意思就是,只要循环结束,线程体结束,那么NSThread也就结束,NSThread中的Runloop也结束了,而不管Runloop中的什么事件有没有执行完

 那么一旦Runloop起来之后,将Runloop中的事件全部移除之后,Runloop是否会自动结束呢

  

- (void)stopThread:(NSThread *)thread
{
    //[self performSelector:@selector(stopThread:) withObject:thread afterDelay:5];
    [_liveTimer invalidate];
    //CFRunLoopStop(CFRunLoopGetCurrent());
    //[thread cancel];
    //_isCancelled = YES;
    //while ([thread isExecuting] == YES) usleep(10000);
    NSLog(@"stop done");
    
}

- (void)ignore:(NSTimer *)timer
{
    NSLog(@"ignore");
}

- (void)threadRun:(NSThread *)thread
{
    NSLog(@"Thread run");
    
     //占用0%的CPU
    
    _liveTimer = [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
                                     target:self
                                   selector:@selector(ignore:)
                                   userInfo:nil
                                    repeats:YES];
     
    
    NSThread *currentThread = [NSThread currentThread];
    NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
    
    _isCancelled = [currentThread isCancelled];

    
    NSLog(@"hello 1");
    while (/*!_isCancelled && */[currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
    {
        NSLog(@"hello 2");
        //_isCancelled = [currentThread isCancelled];
        NSLog(@"hello 4");
    }
    NSLog(@"hello 3");

}

  上面的代码中去除了cancel标记,那么即使timer移除,这个while还在一直保持循环,因为- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;不会返回第二次值

  那么如果没有while循环了呢,这个线程体也就真正结束啦