iOS:常驻线程

常驻线程基本的思路都是等待信号>收到信号>执行回调>继续等待信号,在项目开发中需要将一些耗时的,不紧要的任务放到常驻子线程中处理。
记录两种实现常驻线程的方式:

一、NSThread+RunLoop

- (void)onStart:(UIButton*)sender
{
    NSLog(@"start %@",self.navigationItem.title);
    [NSThread detachNewThreadSelector:@selector(onThread:) toTarget:self withObject:nil];
    
}
 
- (void)onThread:(id)sneder
{
    NSLog(@"run ...");
    self.workerThread_NS = [NSThread currentThread];
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(onCheckNSTask:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] run];
    NSLog(@"over");
}
- (void)onCheckNSTask:(id)sender
{
    NSLog(@"checking ..");
}

或者

- (void)onStart:(UIButton*)sender
{
    NSLog(@"start %@",self.navigationItem.title);
    [NSThread detachNewThreadSelector:@selector(onThread:) toTarget:self withObject:nil];
    
}
 
- (void)onThread:(id)sneder
{
    self.workerThread_NS = [NSThread currentThread];
    // Should keep the runloop from exiting
    CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    
    BOOL runAlways = YES; // Introduced to cheat Static Analyzer
    while (runAlways) {
        
        CFRunLoopRun();
        
    }
    
    // Should never be called, but anyway
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}

二、NSThread+信号量

/**
 常驻线程
 */
@interface ResidentThread : NSObject
-(void)doAction:(dispatch_block_t)action;
-(void)cancel;
@end

@implementation ResidentThread{
    NSMutableArray *actions;
    NSThread *thread;
    dispatch_semaphore_t sem;
    bool cancel;
}
-(id)init{
    self = [super init];
    actions = [NSMutableArray array];
    // 创建信号量
    sem = dispatch_semaphore_create(0);
    // 创建一个新线程
    thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [thread start];
    return self;
}

-(void)run{
    while (true) {
        // 等待信号量,信号量减1
        dispatch_semaphore_wait(sem, -1);
        // 收到信号
        // 如果线程已经取消了,那么退出循环
        if(cancel){
            break;
        }
        // 开始执行任务
        dispatch_block_t block = [actions firstObject];
        if(block){
            [actions removeObject:block];
            block();
        }
        
    }
}

// 执行某个任务
-(void)doAction:(dispatch_block_t)action{
    if(!cancel){ // 如果线程已经cancel了,那么直接忽略
        // 将任务放入数组
        [actions addObject:[action copy]];
        // 发送信号,信号量加1
        dispatch_semaphore_signal(sem);
    }
}

// 终止常驻线程
-(void)cancel{
    cancel = YES;
    // 线程取消后,清空所有的回调
    [actions removeAllObjects];
    // 相当于发送一个终止任务的信号
    dispatch_semaphore_signal(sem);
}
@end

doAction::这个方法接收一个dispatch_block_t的参数,代表实际需要让常驻线程执行的任务。
cancel:终止该常驻线程。
为了安全起见,这里采用的是标记位的方式。另外要注意到,cancel方法里面额外发送了一个信号,这个信号的作用类似于发送了一个终止任务的信号。

你可能感兴趣的:(iOS:常驻线程)