RunLoop 三 : 使用RunLoop线程保活的封装

在RunLoop 二 : RunLoop在实际中的应用篇幅中我们介绍了runloop在项目中的具体用法,并且创建了一个可以控制生命周期的线程.今天我们就用OCC语言两种方法封装一个线程保活的工具类:

一:使用OC语言封装:

// 监控线程生命周期
@interface MYThread : NSThread

@end


@implementation MYThread

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

@end


@interface HHSaveLifeThread ()

@property (nonatomic,strong)MYThread *thread;
///  控制runloop是否停止循环
@property (nonatomic,assign)BOOL isStop;

@end


@implementation HHSaveLifeThread


- (instancetype)init{
    if (self = [super init]) {
        //默认runloop不停止,一直循环
        self.isStop = NO;
        __weak typeof(self) weakSelf = self;
        self.thread = [[MYThread alloc]initWithBlock:^{
            //保住此线程的命,获取当前线程的 runloop ,添加任务
            NSPort *port = [[NSPort alloc]init];
            [[NSRunLoop currentRunLoop]addPort:port forMode:NSDefaultRunLoopMode];
            while (weakSelf && !weakSelf.isStop) {
                [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
        }];
        [self.thread start];
    }
    return self;
}


// 执行任务
- (void)executeTaskWithBlock:(void (^)(void))taskBlock{
    if(!self.thread || !taskBlock) return;
    [self performSelector:@selector(__executeTaskWithBlock:) onThread:self.thread withObject:taskBlock waitUntilDone:NO];
}

// 停止
- (void)stop{
    
    if (!self.thread) return;
    [self performSelector:@selector(__stopRunloop) onThread:self.thread withObject:nil waitUntilDone:YES];
}


- (void)dealloc{
    [self stop];
    NSLog(@"%s",__func__);
}

#pragma mark 私有api
/// 停止 runloop 循环
- (void)__stopRunloop{
    self.isStop = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.thread= nil;
}


- (void)__executeTaskWithBlock:(void (^)(void))taskBlock{
    taskBlock();
}

点击这里下载OC版本demo.

二:使用C语言封装:

// 监控线程生命周期
@interface MYThread : NSThread

@end


@implementation MYThread

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

@end


@interface HHSaveLifeThread ()

@property (nonatomic,strong)MYThread *thread;
///  控制runloop是否停止循环
@property (nonatomic,assign)BOOL isStop;

@end


@implementation HHSaveLifeThread


- (instancetype)init{
    if (self = [super init]) {
        //默认runloop不停止,一直循环
        self.isStop = NO;
        __weak typeof(self) weakSelf = self;
        self.thread = [[MYThread alloc]initWithBlock:^{
            //保住此线程的命,获取当前线程的 runloop ,添加任务
            NSLog(@"-------------start-------------");
            //创建一个上下文环境
            CFRunLoopSourceContext context = {0};
            //创建一个source源
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            //runloop添加source源
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            // 最后一个参数如果为 true : 循环一次后就退出 ,  为 false ,不退出
//            while (weakSelf && !weakSelf.isStop) {
                //启动runloop
                CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1E30, false);
//            }
            NSLog(@"-------------end-------------");
        }];
        [self.thread start];
    }
    return self;
}


// 执行任务
- (void)executeTaskWithBlock:(void (^)(void))taskBlock{
    if(!self.thread || !taskBlock) return;
    [self performSelector:@selector(__executeTaskWithBlock:) onThread:self.thread withObject:taskBlock waitUntilDone:NO];
}

// 停止
- (void)stop{
    
    if (!self.thread) return;
    [self performSelector:@selector(__stopRunloop) onThread:self.thread withObject:nil waitUntilDone:YES];
}


- (void)dealloc{
    [self stop];
    NSLog(@"%s",__func__);
}

#pragma mark 私有api
/// 停止 runloop 循环
- (void)__stopRunloop{
//    self.isStop = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.thread= nil;
}


- (void)__executeTaskWithBlock:(void (^)(void))taskBlock{
    taskBlock();
}

点击这里下载C语言版本demo.

思考:

1. 封装此工具为什么给 NSThread 添加分类这种方式不太好?

答:因为如果使用分类的话,给分类添加属性比较麻烦,需要用到 associate 关联对象这种技术.

2. 为什么不采用继承自 NSThread 这种方式?

答:直接继承自 NSThread 这种方式不太安全,因为 NSThread 类中暴露了很多直接操作 线程 的 API,比如 start,cancle,stop等,其他使用此工具的开发者可能会调动 NSThread 中的方法 打乱 此工具的生命周期.这样的话我们也无法保证线程的声明周期,所以我们继承自 NSObject 更好一些.把线程操作相关的方法封装起来,更安全.

你可能感兴趣的:(RunLoop 三 : 使用RunLoop线程保活的封装)