iOS 根据多线程&RunLoop创建常驻子线程

253 阅读1分钟

创建常驻子线程

说明:

将线程对象中添加runLoop,runLoop中添加port(抽象端口消息收发),成为常驻子线程。

销毁常驻子线程

说明:

原理为管理runloop状态并释放runloop循环,不再常驻,线程随之自动释放。

注:不可以直接移除port或强制杀死thread,容易产生野指针。

举例

#import "thread.h"
@interface thread()
@property(nonatomic,assign)BOOL shouldStopRun;
@property(nonatomic,strong)NSPort *port;
@property(nonatomic,strong)NSThread *thread;
@end

@implementation thread
- (void)done{
    self.shouldStopRun = NO;
    self.port = [NSMachPort port];
    //添加runLoop,抽象端口port消息收发,成为常驻子线程
    self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(AddRunLoop) object:nil];
    [self.thread start];
}

- (void)AddRunLoop{
    //TLS:线程局部存储空间,只能被当前线程访问
    @autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:self.port forMode:NSDefaultRunLoopMode];
        //2秒后释放runloop两层循环,不再常驻,释放线程
        [self performSelector:@selector(RemoveRunLoop) withObject:nil afterDelay:2];
        //执行并等待释放
        //[runloop run]; 底层源码等价于[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]
        while (!self.shouldStopRun && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    }
}

- (void)RemoveRunLoop{
    //正确释放
    self.shouldStopRun = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    //错误释放(移除当前source事件时,不会保证系统不会向runloop中添加其他事件源,会产生野指针)
    //    [[NSRunLoop currentRunLoop] removePort:self.port forMode:NSDefaultRunLoopMode];
    //错误释放(thread被释放,但runloop仍存活,会产生野指针)
    //    [NSThread exit];
}

@end