iOS:常驻线程

作者: 丶墨墨丶 | 来源:发表于2019-08-15 17:05 被阅读0次

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

    一、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:常驻线程

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