美文网首页iOS开发技巧
利用 NSRunLoop 对线程保活

利用 NSRunLoop 对线程保活

作者: CoderGuogt | 来源:发表于2019-09-30 11:31 被阅读0次

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

    技术点

    • 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<UITouch *> *)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 <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)}
      -[YXCController dealloc]
      end <YXCThread: 0x600003d033c0>{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 对线程保活

        本文链接:https://www.haomeiwen.com/subject/ofvcpctx.html