iOS 创建常驻线程

作者: 包砸豆沙馅 | 来源:发表于2021-04-01 19:57 被阅读0次

    iOS中默认就有个主线程即mainThread,我们的UI线程指的就是主线程,一般都是在主线程中操作UI,从某个角度来讲,我们的主线程就是一个常驻线程。

    一般情况下,我们开启一个子线程,让子线程去跑一个任务,当任务执行完毕之后,该线程就会被系统自动销毁。假如说 在一个遍历循环中,要执行10000次创建子线程去执行一个耗时任务,那么这么频繁的去创建和销毁线程就会造成资源的浪费,那我们为什么不让频繁使用的子线程常驻在内存中,想用的时候就用,不想用的时候让他休眠呢?

    接下来就示例创建一个常驻线程。

    • 首先创建一个ThreadManager类,为类添加一个暴露类属性,一个隐私类属性:
    @interface ThreadManager : NSObject
    @property (nonatomic, assign, class) BOOL isShouldKeepRunning;
    @end
    
    @interface ThreadManager()
    @property (nonatomic, strong, class) NSThread * residentThread;
    @end
    

    其中isShouldKeepRuning属性可以用来控制当前子线程中runloop是否停止
    residentThread为要创建引用的常驻线程

    • 接下来 声明一个静态变量,开辟空间
    static BOOL _isShouldKeepRuning;
    static NSThread * _residentThread;
    

    为其提供getter和setter方法

    + (BOOL)isShouldKeepRunning {
        return _isShouldKeepRuning;
    }
    
    + (void)setIsShouldKeepRunning:(BOOL)isShouldKeepRunning {
        _isShouldKeepRuning = isShouldKeepRunning;
    }
    
    + (NSThread *)residentThread {
        if (_residentThread == nil) {
            // thread方法为创建线程的方法,下面会写到。
            _residentThread = [self thread];
        }
        return _residentThread;
    }
    
    + (void)setResidentThread:(NSThread *)residentThread {
        _residentThread = residentThread;
    }
    

    提供线程创建的方法 以及在子线程中获取runloop

    + (NSThread *)thread {
        NSThread * thread = nil;
        __weak typeof(self)weakSelf = self;
        void(^creatThreadBlock)(void) = ^{
            NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
            [currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
            while (weakSelf && weakSelf.isShouldKeepRunning) {
                [currentLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
            NSLog(@"runloop 停止! ! !");
        };
        self.isShouldKeepRunning = YES;
        if (@available(iOS 10.0, *)) {
            thread = [[NSThread alloc] initWithTarget:self selector:@selector(creatThreadMethod:) object:creatThreadBlock];
        } else {
            thread = [[NSThread alloc] initWithBlock:creatThreadBlock];
        }
        thread.name = @"thread_resident";
        [thread start];
        return thread;
    }
    
    + (void)creatThreadMethod:(void(^)(void))task {
        if (task) {
            task();
        }
    }
    
    + (void)executeTask:(void(^)(void))task {
        [self performSelector:@selector(threadTaskMethod:) onThread:self.residentThread withObject:task waitUntilDone:NO];
    }
    
    + (void)threadTaskMethod:(void(^)(void))task {
        if (task) {
            NSLog(@"currentThread: %@", [NSThread currentThread]);
            task();
        }
    }
    
    

    其中

    NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
    [currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    
    • RunLoop只能获取,不能创建。 在子线程中,获取runloop,如果没有, 系统会为我们创建,如果currentLoop中没有 source0事件、source1事件、定时器、obsever 这些事件资源,那么RunLoop不会循环,会直接结束,所以要给RunLoop加一个监听端口,用来监听系统事件的发生,那么这样子才能够保证RunLoop一直循环不退出。
    • 最后将+ (void)executeTask:(void(^)(void))task; 方法暴露出来,外部就可以直接拿来使用。下面是我测试的代码和测试结果
     [ThreadManager executeTask:^{
            NSLog(@"1 1 1 子线程 执行操作 ");
        }];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [ThreadManager executeTask:^{
                NSLog(@"2 2 2 子线程 执行操作 ");
            }];
        });
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [ThreadManager executeTask:^{
                NSLog(@"3 3 3 子线程 执行操作 ");
            }];
        });
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            ThreadManager.isShouldKeepRunning = NO;
        });
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [ThreadManager executeTask:^{
                NSLog(@"4 4 4 子线程 执行操作 ");
            }];
        });
    

    结果如下:


    常驻线程执行
    • 可见任务的执行都在同一个子线程当中,当改变isShouldKeepRunning的值,在下一次RunLoop循环的时候,RunLoop循环被打破,退出RunLoop,此时常驻线程也不复存在。
    • 后续也可以再扩展一个方法用来重新掉起一条新的常驻线程,那么可以达到在某些情况下,已经执行了很多任务,用不到这个线程,不想让这个线程在内存中存在,手动给销毁掉,在用到的时候 重新创建。

    相关文章

      网友评论

        本文标题:iOS 创建常驻线程

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