美文网首页
利用runLoop开启一条可以控制生命周期的子线程

利用runLoop开启一条可以控制生命周期的子线程

作者: ZZ_军哥 | 来源:发表于2022-03-04 14:56 被阅读0次

先上代码,我在上面都加了注释:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface GYJThread : NSObject

///在子线程执行任务
- (void)excuteAction:(void(^)(void))task;
///销毁runloop和子线程
- (void)stop;

@end
#import "GYJThread.h"

@interface textThread : NSThread

@end

@implementation textThread

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

@property(nonatomic,strong)textThread *thread;

@end
@implementation GYJThread

- (instancetype)init
{
    if (self = [super init]) {
        
        //开启一条线程
        self.thread = [[textThread alloc]initWithBlock:^{
            NSLog(@"runloop开启");
            //runloop与线程一一对应,通过获取方式,底层就会去创建,类似于懒加载
            CFRunLoopRef runloop = CFRunLoopGetCurrent();
            
            //添加timer source block的方式,用以让runloop处理事情,CFRunLoopSourceContext结构体,初始化结构体,类似int a = 0;
            CFRunLoopSourceContext context = {0};
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            //添加的source已默认模式处理(默认模式/滚动模式)
            CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
            //释放创建的source (source0 source1 响应点击等操作的内容就放在source中,timer定时器)
            CFRelease(source);
            //让runloop工作,1.0e10代表一个很大的时间(让runloop一直工作),false代表runloop处理该消息后不退出,如果传true,马上就会打印runloop结束,传false是需要runloop一直卡在这
            //CFRunLoopRun()  该api会导致runloop一直存在,不会销毁,我们控制不了他销毁,所以用CFRunLoopRunInMode
            CFRunLoopRunInMode(kCFRunLoopDefaultMode,1.0e10, false);
            NSLog(@"runloop结束");
        }];
        //开启线程
        [self.thread start];
    }
    return self;
}
///在子线程执行任务
- (void)excuteAction:(void(^)(void))task
{
    if (!self.thread) return;
    //在子线程执行任务waitUntilDone:传NO 代表主线程和当前任务互不干扰,传YES代表必须执行完这个任务 主线程才会往下走
    [self performSelector:@selector(priviteExcuteAction:) onThread:self.thread withObject:task waitUntilDone:NO];
}
///销毁runloop和子线程
- (void)stop
{
    if (!self.thread) return;
    //在子线程执行任务waitUntilDone:传NO 代表主线程和当前任务互不干扰,传YES代表必须执行完这个任务 主线程才会往下走
    [self performSelector:@selector(priviteStop) onThread:self.thread withObject:nil waitUntilDone:YES];
}

- (void)priviteExcuteAction:(void(^)(void))task
{
    NSLog(@"当前线程%@",[NSThread currentThread]);
    task();
}
- (void)priviteStop
{
    //关闭runloop
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.thread = nil;
}

- (void)dealloc
{
    [self stop];
}

@end

然后新建2个控制器,用以来验证runloop和控制器,线程的生命周期


image.png
image.png

代码比较简单,ViewController1中间加了个按钮,点击push到ViewController2中
ViewController2中间加了个停止线程按钮,点击屏幕会执行任务

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor yellowColor];
    self.stopBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    self.stopBtn.center = self.view.center;
    [self.view addSubview:self.stopBtn];
    [self.stopBtn setTitle:@"停止线程" forState:UIControlStateNormal];
    [self.stopBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [self.stopBtn addTarget:self action:@selector(stop) forControlEvents:UIControlEventTouchUpInside];
    
    self.customThread = [[GYJThread alloc]init];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.customThread excuteAction:^{
        NSLog(@"执行任务");
    }];
}

- (void)stop
{
    [self.customThread stop];
}

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

A.进入ViewController2,点击空白屏幕,再点击停止按钮


image.png

可以看到任务都是在同一条子线程执行,点击停止,runloop和线程都销毁了,此时再点击空白屏幕,不会有反应了,为了防止多次点击按钮导致奔溃,所以在执行任务和stop都做一个判断,防止点击一次按钮后,东西都销毁了,再次点击,导致奔溃

B.进入ViewController2,点击空白屏幕,直接点击返回按钮


image.png

可以看到子线程,runloop,都会跟随ViewController2的销毁一起销毁

这个类可以包装成工具,其中的打印信息和textThread(都是为了调试用),后面是可以删除打印信息并将textThread替换成NSThread的,好了,分享完毕

相关文章

  • 利用runLoop开启一条可以控制生命周期的子线程

    先上代码,我在上面都加了注释: 然后新建2个控制器,用以来验证runloop和控制器,线程的生命周期 代码比较简单...

  • 实现后台常驻线程

    添加一条用于常驻内存的强引用的子线程,在该线程的RunLoop下添加一个Sources,开启RunLoop。

  • 使用什么方式使子线程永驻

    1、NSThread+RunLoop 如上图所示:创建一个子线程,然后开启子线程的runloop既可以达到子线程永...

  • RunLoop-线程保活

    01 AFNetWorking,它既是使用runloop来控制线程的生命周期,让子线程一直停留在内存当中,这样在子...

  • 10.3 runloop 的实际应用

    runloop实际中的应用 控制线程生命周期(线程保活)、崩溃的起死回生 runloop和performselec...

  • iOS开发中的运行循环机制

    RunLoop的概念 每一个线程都有一个RunLoop对象,主线程默认开启RunLoop,子线程默认不开启。 ru...

  • IOS内存管理--自动释放池的实现原理

    默认主线的运行循环(runloop)是开启的,子线程的运行循环(runloop)默认是不开启的,也就意味着子线程中...

  • iOS RunLoop

    一、什么是RunLoop RunLoop就是控制线程生命周期并接收事件进行处理的机制。RunLoop是iOS事件响...

  • 关于Runloop一些面试题的整理

    1.Runloop和线程的关系? 一个线程对应一个Runloop。 主线程默认开启了Runloop。 子线程的Ru...

  • 多线程篇

    因为performSelector方法是需要依赖线程runLoop,但是开辟的子线程默认是没有开启runLoop的...

网友评论

      本文标题:利用runLoop开启一条可以控制生命周期的子线程

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