Runloop线程常驻

Posted 梦想家-mxj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Runloop线程常驻相关的知识,希望对你有一定的参考价值。

ios开发过程中,有时一些花费时间比较长的操作阻塞主线程,导致界面卡顿,那么我们就会创建一个子线程,然后把这些花费时间比较长的操作放在子线程中来处理。可是当子线程中的任务执行完毕后,子线程就会被销毁掉。

如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁线程,会造成资源的浪费。
这时候我们就可以使用RunLoop来让该线程长时间存活而不被销毁。

来个案例,在睡眠时,通过硬件获取数据信息(比如心电信息),开始睡眠时,创建runloop,使得子线程常驻,用于写数据到文件
睡眠结束后,退出runloop

iOS开发-RunLoop的退出方式
开启方法:

- (void)run; 
- (void)runUntilDate:(NSDate *)limitDate;
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;

这三种方式无论通过哪一种方式启动runloop,如果没有一个输入源或者timer附加于runloop上,runloop就会立刻退出。
  (1) 第一种方式,runloop会一直运行下去,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;
  (2) 第二种方式,可以设置超时时间,在超时时间到达之前,runloop会一直运行,在此期间runloop会处理来自输入源的数据,并且也会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;
  (3) 第三种方式,runloop会运行一次,超时时间到达或者第一个input source被处理,则runloop就会退出。
前两种启动方式会重复调用runMode:beforeDate:方法。
二. 退出RunLoop的方式
第一种启动方式的退出方法
文档说,如果想退出runloop,不应该使用第一种启动方式来启动runloop。
如果runloop没有input sources或者附加的timer,runloop就会退出。
虽然这样可以将runloop退出,但是苹果并不建议我们这么做,因为系统内部有可能会在当前线程的runloop中添加一些输入源,所以通过手动移除input source或者timer这种方式,并不能保证runloop一定会退出。
第二种启动方式runUntilDate:
  可以通过设置超时时间来退出runloop。
第三种启动方式runMode:beforeDate:
通过这种方式启动,runloop会运行一次,当超时时间到达或者第一个输入源被处理,runloop就会退出。
如果我们想控制runloop的退出时机,而不是在处理完一个输入源事件之后就退出,那么就要重复调用runMode:beforeDate:,

所以:

开始睡眠:
- (void)sleepStart{
//创建线程
    NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(subThreadEnter) object:nil];
    [subThread setName:@"子线程"];
    [subThread start];
    self.ttThread = subThread;
 [self performSelector:@selector(subThreadAction) onThread:self.ttThread withObject:nil waitUntilDone:NO];
}
/**
 子线程启动后,启动runloop
 */
- (void)subThreadEnter
{
//给这个线程分配任务就是唤醒车这个线程的一个source RunLoop Mode就是一系列输入的source ,timer和以及observer
    @autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        //如果注释了下面这一行,子线程中的任务并不能正常执行
        [runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
        NSLog(@"启动RunLoop前--%@",runLoop.currentMode);
        self.runLoop = runLoop;
        isLoopRunning = YES;
        while (isLoopRunning){
            [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        };
    }
}
//读写数据
- (void)readWriteData{
    @autoreleasepool {
        NSLog(@"%@----子线程",[NSThread currentThread]);
        //写数据
        NSLog(@"写入raw");
        NSLog(@"写入other");
        NSLog(@"写入detail");
    }
}
//在获取到数据时就写入到文件
 [self performSelector:@selector(readWriteData) onThread:self.ttThread withObject:nil waitUntilDone:NO];
停止睡眠时
- (void)sleepStop{
    isLoopRunning = NO;
  CFRunLoopStop(CFRunLoopGetCurrent());
}

这样,我们在开始睡眠的方法里使得当前子线程常驻,用于把数据信息不断地写入到文件中,当睡眠结束后,退出当前loop即可。

以上是关于Runloop线程常驻的主要内容,如果未能解决你的问题,请参考以下文章

Runloop线程常驻

Runloop线程常驻

iOS 常驻线程

创建一个常驻线程

RunLoop总结:RunLoop的应用场景

你了解 RunLoop 线程保活吗?已封装好,2 句代码直接使用