美文网首页
detachNewThreadSelector 方法

detachNewThreadSelector 方法

作者: 多喝热开水 | 来源:发表于2020-04-21 08:58 被阅读0次

    今天一个小伙伴问我以下代码会不会打印"—"

    [NSThread detachNewThreadSelector:@selector(runA:) toTarget:self withObject:@"分离子线程"];
    -(void)runA:(NSString *)param {
        [self performSelector:@selector(onTask) withObject:nil afterDelay:2.0];
    }
    -(void)onTask {
        NSLog(@"—");
    }
    

    答案当然是不能。
    我之前在说过类似的问题,在一个新的线程中 延迟2s对self发送消息。发现无论怎么发送这个通知,通知都不会回调,这个是因为并没有为该子线程添加runloop,这个线程触发之后马上就结束了。(没有添加通知队列的时候,是可以回调到的,因为那种情况下,通知发送后,通知回调马上就会执行,该线程会等待通知回调执行完毕后才结束).

    1.我们可以选择获取主线程,在主线程中执行该方法

    //回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            [self performSelector:@selector(onTask) withObject:nil afterDelay:2.0];
       });
    
    1. 保证新的线程不被释放
      我们需要添加为子线程添加一个runloop,让子线程常驻:
    @property (nonatomic, strong) NSThread *thread;
    
    [self performSelector:@selector(runA:) onThread:self.thread withObject:@"分离子线程" waitUntilDone:YES];
    
    - (NSThread *)thread {
        if (!_thread) {
            _thread = [[NSThread alloc] initWithBlock:^{
                NSRunLoop *ns_runloop = [NSRunLoop currentRunLoop];
                [ns_runloop addPort:[NSPort port] forMode:NSRunLoopCommonModes];
    
                CFRunLoopRef runloop = CFRunLoopGetCurrent();
                CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
                    switch (activity) {
                        case kCFRunLoopEntry:
                            NSLog(@"进入runLoop");
                            break;
                        case kCFRunLoopBeforeTimers:
                            NSLog(@"处理timer事件");
                            break;
                        case kCFRunLoopBeforeSources:
                            NSLog(@"处理source事件");
                            break;
                        case kCFRunLoopBeforeWaiting:
                            NSLog(@"进入睡眠");
                            break;
                        case kCFRunLoopAfterWaiting:
                            NSLog(@"被唤醒");
                            break;
                        case kCFRunLoopExit:
                            NSLog(@"退出");
                            break;
                        default:
                            break;
                    }
                });
                CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
                CFRelease(observer);
                [ns_runloop run];
            }];
            [_thread start];
        }
        return _thread;
    }
    
    -(void)runA:(NSString *)param
    {
        NSLog(@"callFunction");
        [self performSelector:@selector(onTask) withObject:nil afterDelay:2.0];
    }
    -(void)onTask {
        NSLog(@"—");
    }
    
    

    能清晰的看到log:

    2020-04-21 08:45:46.725300+0800 copy[4755:708949] 进入runLoop
    2020-04-21 08:45:46.725378+0800 copy[4755:708949] 处理timer事件
    2020-04-21 08:45:46.725415+0800 copy[4755:708949] 处理source事件
    2020-04-21 08:45:46.725444+0800 copy[4755:708949] callFunction
    2020-04-21 08:45:46.725528+0800 copy[4755:708949] 退出
    2020-04-21 08:45:46.725608+0800 copy[4755:708949] 进入runLoop
    2020-04-21 08:45:46.725640+0800 copy[4755:708949] 处理timer事件
    2020-04-21 08:45:46.726288+0800 copy[4755:708949] 处理source事件
    2020-04-21 08:45:46.726684+0800 copy[4755:708949] 进入睡眠
    2020-04-21 08:45:48.726685+0800 copy[4755:708949] 被唤醒
    2020-04-21 08:45:48.727276+0800 copy[4755:708949] —
    2020-04-21 08:45:48.728429+0800 copy[4755:708949] 处理timer事件
    2020-04-21 08:45:48.729327+0800 copy[4755:708949] 处理source事件
    2020-04-21 08:45:48.729693+0800 copy[4755:708949] 进入睡眠
    

    相关文章

      网友评论

          本文标题:detachNewThreadSelector 方法

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