利用 NSRunLoop 对线程保活

在开发场景中,有可能需要对某条线程保活,让这条线程在有事情做的时候进行工作,没有事情做的时候进行休眠。

技术点

  • NSRunLoop
  • NSTread
  1. 利用 NSThread 创建一条线程,并且在这条线程创建一个 RunLoop,并创建一个 source,防止 RunLoop退出,这里也可以新建一个集成于 NSThread 的类,观察NSThread是否被释放,同时创建一个标志属性stopped初始值为 NO来判断是否要退出 RunLoop.

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor whiteColor];
        self.stopped = NO;
    
        __weak typeof(self) weakSelf = self;
        self.thread = [[YXCThread alloc] initWithBlock:^{
            // 给当前线程创建一个 runLoop ,并且创建一个 source
            NSLog(@"beigin %@", [NSThread currentThread]);
            [[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
            while (weakSelf && !weakSelf.isStopped) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
            NSLog(@"end %@", [NSThread currentThread]);
        }];
        // 线程开启
        [self.thread start];
    }
    
  2. 紧接着,模拟做事情,这里选择是在 touchesBegan:withEvent: 去模拟做一些事情

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        
        if (!self.thread) return;
        // waitUntilDone 这里可以传 NO,不需要等待当前操作执行完成
        [self performSelector:@selector(doSomeThing) onThread:self.thread withObject:nil waitUntilDone:NO];
    }
    
    - (void)doSomeThing {
        
        NSLog(@"%s, %@", __func__, [NSThread currentThread]);
    }
    
  3. 最后在 ViewController 中的 dealloc 方法中,停止 runLoop 和 释放线程操作

    - (void)dealloc {
        
        NSLog(@"%s", __func__);
        // waitUntilDone 这里需要传 YES,等待操作完成了,再继续执行,不然控制器释放了,会崩溃
        [self performSelector:@selector(stop) onThread:self.thread withObject:nil waitUntilDone:YES];
    }
    
  4. 最后输出结果

    beigin {number = 7, name = (null)}
    -[YXCController doSomeThing], {number = 7, name = (null)}
    -[YXCController doSomeThing], {number = 7, name = (null)}
    -[YXCController doSomeThing], {number = 7, name = (null)}
    -[YXCController doSomeThing], {number = 7, name = (null)}
    -[YXCController doSomeThing], {number = 7, name = (null)}
    -[YXCController dealloc]
    end {number = 7, name = (null)}
    -[YXCThread dealloc]
    

这样,就对一条线程保活完成了,最后控制器释放了,Thread也释放了,RunLoop也释放了

下面,可以进行封装一下

新建一个 YXCPermanentThread

.h 文件

@interface YXCPermanentThread : NSObject

#pragma mark - Method

- (void)executeTask:(void (^)(void))task;

@end

.m 文件

#pragma mark ====== YXCThread ======

@interface YXCThread : NSThread

@end

@implementation YXCThread

- (void)dealloc {
    
    NSLog(@"%s", __func__);
}

@end

#pragma mark ====== YXCPermanentThread ======

@interface YXCPermanentThread ()

@property (nonatomic, strong) YXCThread *thread; /**< 开辟子线程 */
@property (nonatomic, assign, getter=isStopped) BOOL stopped; /**< 是否停止runLoop */

@end

@implementation YXCPermanentThread

- (instancetype)init {
    
    if (self = [super init]) {
        
        self.stopped = NO;
        __weak typeof(self) weakSelf = self;
        self.thread = [[YXCThread alloc] initWithBlock:^{
            NSLog(@"-- beigin -- %@", [NSThread currentThread]);
            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
            while (weakSelf && !weakSelf.isStopped) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
            NSLog(@"-- end -- %@", [NSThread currentThread]);
        }];
        [self.thread start];
    }
    
    return self;
}

- (void)dealloc {
    
    NSLog(@"%s", __func__);
    [self performSelector:@selector(__stop) onThread:self.thread withObject:nil waitUntilDone:YES];
}

- (void)executeTask:(void (^)(void))task {
    
    if (!self.thread) return;
    [self performSelector:@selector(__executeTask:) onThread:self.thread withObject:task waitUntilDone:NO];
}

- (void)__stop {
    
    if (!self.thread) return;
    self.stopped = NO;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.thread = nil;
}

- (void)__executeTask:(void (^)(void))task {
    
    task();
}

如果需要使用就只需要创建一个 YXCPermanentThread 实例对象,把需要的操作通过 executeTask:方法传入进去,然后其他的都不需要再操作了。当然也可以在.h文件中添加一个停止的方法,对RunLoop进行停止操作。

你可能感兴趣的:(利用 NSRunLoop 对线程保活)