IOS知识积累iOS技术点多线程

# iOS线程保活(常驻线程)

2019-01-03  本文已影响26人  Jason_YZC

介绍

在日常的iOS开发中,遇到卡顿也是在所难免,一般卡顿是由于主线程处理耗时长的操作而造成线程一直在阻塞,那么我们可以去建立子线程,把耗时操作放在子线程去做,这样是完全没问题。 这样就会有一个问题,子线程处理完操作之后就会被销毁,想再处理其他事情,必须再开启新的子线程。如果想要一个子线程去持续处理事情,那么就需要这个线程一直存活在后台,在需要的时候随时可以唤醒。

下面提供两种线程保活的方案就可以做到保活,在有任务的时候唤醒来做事情, 线程没任务时会进入休眠状态。

方案一

//头文件
typedef void (^YZCPermenantThreadTask)(void);

@interface YZCPermenantThread : NSObject

- (void)executeTask:(YZCPermenantThreadTask)task;

- (void)cancelTask;
@end


//==========.m文件================
#import "YZCPermenantThread.h"

#pragma mark - YZCThread
@interface YZCThread : NSThread
@end
@implementation YZCThread
-(void)dealloc {
    NSLog(@"%s",__func__);
}
@end

#pragma mark - YZCPermenantThread
@interface YZCPermenantThread()
@property (nonatomic, strong) YZCThread *innerThread;
@property (nonatomic, assign, getter=isStopped) BOOL stopped;
@end


@implementation YZCPermenantThread

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.stopped = NO;
        
        __weak typeof(self) weakSelf = self;
        self.innerThread = [[YZCThread alloc] initWithBlock:^{
            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init]
                                        forMode:NSDefaultRunLoopMode];
            
            while (weakSelf && !weakSelf.isStopped) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                         beforeDate:[NSDate distantFuture]];
            }
        }];
        
        [self.innerThread start];
    }
    return self;
}

- (void)executeTask:(YZCPermenantThreadTask)task {
    if (!self.innerThread || !task) return;
    
    [self performSelector:@selector(__executeTask:) onThread:self.innerThread
               withObject:task waitUntilDone:NO];
}

- (void)cancelTask {
    if (!self.innerThread) return;
    [self performSelector:@selector(stop) onThread:self.innerThread
               withObject:nil waitUntilDone:YES];
}

#pragma mark - private
- (void)stop {
    self.stopped = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThread = nil;
}

- (void)__executeTask:(YZCPermenantThreadTask)task {
    task();
}

方案二

方案二只是核心实现不一样,其他基本一致,相比方案一去除了标记,直接使用CFRunLoop去做

- (instancetype)init
{
    if (self = [super init]) {
        self.innerThread = [[YZCPermenantThread alloc] initWithBlock:^{
            NSLog(@"begin----");
            
            // 创建上下文(要初始化一下结构体)
            CFRunLoopSourceContext context = {0};
            
            // 创建source
            CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
            
            // 往Runloop中添加source
            CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
            
            // 销毁source
            CFRelease(source);
            
            // 启动
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false);
            
            NSLog(@"end----");
        }];
        
        [self.innerThread start];
    }
    return self;
}

调用

外面调用就相对比较简单,因为上面已经封装好了

#import "ViewController.h"
#import "YZCPermenantThread.h"

@interface ViewController ()
@property (nonatomic, strong) YZCPermenantThread *thread;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.thread = [[YZCPermenantThread alloc] init];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.thread executeTask:^{
        NSLog(@"执行了任务:%@",[NSThread currentThread]);
    }];
}
上一篇下一篇

猜你喜欢

热点阅读