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

保证线程的长时间存活
在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

发表评论

电子邮件地址不会被公开。 必填项已用*标注