iOS 创建常驻线程

iOS中默认就有个主线程即mainThread,我们的UI线程指的就是主线程,一般都是在主线程中操作UI,从某个角度来讲,我们的主线程就是一个常驻线程。

一般情况下,我们开启一个子线程,让子线程去跑一个任务,当任务执行完毕之后,该线程就会被系统自动销毁。假如说 在一个遍历循环中,要执行10000次创建子线程去执行一个耗时任务,那么这么频繁的去创建和销毁线程就会造成资源的浪费,那我们为什么不让频繁使用的子线程常驻在内存中,想用的时候就用,不想用的时候让他休眠呢?

接下来就示例创建一个常驻线程。

  • 首先创建一个ThreadManager类,为类添加一个暴露类属性,一个隐私类属性:
@interface ThreadManager : NSObject
@property (nonatomic, assign, class) BOOL isShouldKeepRunning;
@end
@interface ThreadManager()
@property (nonatomic, strong, class) NSThread * residentThread;
@end

其中isShouldKeepRuning属性可以用来控制当前子线程中runloop是否停止
residentThread为要创建引用的常驻线程

  • 接下来 声明一个静态变量,开辟空间
static BOOL _isShouldKeepRuning;
static NSThread * _residentThread;

为其提供getter和setter方法

+ (BOOL)isShouldKeepRunning {
    return _isShouldKeepRuning;
}

+ (void)setIsShouldKeepRunning:(BOOL)isShouldKeepRunning {
    _isShouldKeepRuning = isShouldKeepRunning;
}

+ (NSThread *)residentThread {
    if (_residentThread == nil) {
        // thread方法为创建线程的方法,下面会写到。
        _residentThread = [self thread];
    }
    return _residentThread;
}

+ (void)setResidentThread:(NSThread *)residentThread {
    _residentThread = residentThread;
}

提供线程创建的方法 以及在子线程中获取runloop

+ (NSThread *)thread {
    NSThread * thread = nil;
    __weak typeof(self)weakSelf = self;
    void(^creatThreadBlock)(void) = ^{
        NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
        [currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        while (weakSelf && weakSelf.isShouldKeepRunning) {
            [currentLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
        NSLog(@"runloop 停止! ! !");
    };
    self.isShouldKeepRunning = YES;
    if (@available(iOS 10.0, *)) {
        thread = [[NSThread alloc] initWithTarget:self selector:@selector(creatThreadMethod:) object:creatThreadBlock];
    } else {
        thread = [[NSThread alloc] initWithBlock:creatThreadBlock];
    }
    thread.name = @"thread_resident";
    [thread start];
    return thread;
}

+ (void)creatThreadMethod:(void(^)(void))task {
    if (task) {
        task();
    }
}

+ (void)executeTask:(void(^)(void))task {
    [self performSelector:@selector(threadTaskMethod:) onThread:self.residentThread withObject:task waitUntilDone:NO];
}

+ (void)threadTaskMethod:(void(^)(void))task {
    if (task) {
        NSLog(@"currentThread: %@", [NSThread currentThread]);
        task();
    }
}

其中

NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
[currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
  • RunLoop只能获取,不能创建。 在子线程中,获取runloop,如果没有, 系统会为我们创建,如果currentLoop中没有 source0事件、source1事件、定时器、obsever 这些事件资源,那么RunLoop不会循环,会直接结束,所以要给RunLoop加一个监听端口,用来监听系统事件的发生,那么这样子才能够保证RunLoop一直循环不退出。
  • 最后将+ (void)executeTask:(void(^)(void))task; 方法暴露出来,外部就可以直接拿来使用。下面是我测试的代码和测试结果
 [ThreadManager executeTask:^{
        NSLog(@"1 1 1 子线程 执行操作 ");
    }];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"2 2 2 子线程 执行操作 ");
        }];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"3 3 3 子线程 执行操作 ");
        }];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        ThreadManager.isShouldKeepRunning = NO;
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"4 4 4 子线程 执行操作 ");
        }];
    });

结果如下:


常驻线程执行
  • 可见任务的执行都在同一个子线程当中,当改变isShouldKeepRunning的值,在下一次RunLoop循环的时候,RunLoop循环被打破,退出RunLoop,此时常驻线程也不复存在。
  • 后续也可以再扩展一个方法用来重新掉起一条新的常驻线程,那么可以达到在某些情况下,已经执行了很多任务,用不到这个线程,不想让这个线程在内存中存在,手动给销毁掉,在用到的时候 重新创建。

你可能感兴趣的:(iOS 创建常驻线程)