iOS开发-使用Runloop实现线程保活、线程常驻

来源:互联网 发布:火猫解说 收入 知乎 编辑:程序博客网 时间:2024/05/29 19:04

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

首先,我们创建一个testThread类,继承自NSThread,然后重写dealloc 方法。

@interface testThread : NSThread@end@implementation testThread- (void)dealloc{    NSLog(@"%s",__func__);}@end
- (void)viewDidLoad {    [super viewDidLoad];    // 测试线程    [self threadTest];}- (void)threadTest{    testThread *subThread = [[testThread alloc] initWithTarget:self selector:@selector(subThreadAction) object:nil];    [subThread start];}- (void)subThreadAction{    @autoreleasepool {        NSLog(@"%@----子线程任务开始",[NSThread currentThread]);        [NSThread sleepForTimeInterval:2.0];        NSLog(@"%@----子线程任务结束",[NSThread currentThread]);    }}

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

#import "SubViewController.h"#import "testThread.h"@interface SubViewController ()@property(nonatomic,strong) testThread* ttThread;@end@implementation SubViewController- (void)viewDidLoad {    [super viewDidLoad];    // 测试线程    [self threadTest];}- (void)threadTest{    testThread *subThread = [[testThread alloc] initWithTarget:self selector:@selector(subThreadEnter) object:nil];    [subThread setName:@"测试线程"];    [subThread start];    self.ttThread = subThread;}/** 子线程任务 */- (void)subThreadAction{    NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);    NSLog(@"%@----子线程任务开始",[NSThread currentThread]);    for (int i=0; i<300; i++)    {        [NSThread sleepForTimeInterval:1.0];        NSLog(@"----子线程任务 %ld",(long)i);    }    NSLog(@"%@----子线程任务结束",[NSThread currentThread]);}/** 子线程启动后,启动runloop */- (void)subThreadEnter{    @autoreleasepool {        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];        //如果注释了下面这一行,子线程中的任务并不能正常执行        [runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];        NSLog(@"启动RunLoop前--%@",runLoop.currentMode);        [runLoop run];    }}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    [self performSelector:@selector(subThreadAction) onThread:self.ttThread withObject:nil waitUntilDone:NO];}@end

1.获取RunLoop只能使用 [NSRunLoop currentRunLoop] 或 [NSRunLoop mainRunLoop];
2.即使RunLoop开始运行,如果RunLoop 中的 modes 为空,或者要执行的mode里没有item,那么RunLoop会直接在当前loop中返回,并进入睡眠状态。
3.自己创建的Thread中的任务是在kCFRunLoopDefaultMode这个mode中执行的。
4.在子线程创建好后,最好所有的任务都放在AutoreleasePool中。

如果不执行下列语句:
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];

不执行.png

执行下列语句:
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];

执行后.png

可以看出我们添加了一个source0,这样runloop才运行起来。

其实这个例子只是简单制造一个常驻内存的线程,但是这个线程并不好控制结束,可以参考我的另外一篇文章iOS开发-RunLoop的退出方式。

原创粉丝点击