请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

子线程开启runLoop为啥放在上面不好使?

   - (void)performClicked
{
    NSLog(@"performClicked");
}

 dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"进入异步线程");
    NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
    [runLoop run];

    [self performSelector:@selector(performClicked) withObject:nil afterDelay:1];
    
});

这样写不打印 performClicked 把开启runLoop的代码放下面就好使了这样:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"进入异步线程");
    [self performSelector:@selector(performClicked) withObject:nil afterDelay:1];
     NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
    [runLoop run];

});

就会执行打印,为啥?

正在回答 回答被采纳积分+3

1回答

于海 2020-04-06 13:38:19

先回答你下面代码的问题

dispatch_async(dispatch_get_global_queue(0, 0), ^{
   NSLog(@"进入异步线程");

// 老师注解:该方法调用将在delay时间后在当前线程的 defaultMode下分派执行

// 这相当于向当前runLoop提交了一个Soure/Timer/Port

This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.

上述系统注释翻译过来就是

该方法设置一个定时器,在当前线程的runloop里执行selector方法,定时器会被配置在default Mode下运行。当定时器启动的时候,当前线程试图从runloop中取出消息然后执行该选择器。如果当前runloop正在运行并且是在default Mode下运行,那么可以成功执行。否则,需要等到runloop在defaultmode下运行时才能有机会执行。

注意这方法只是做了配置并不会创建runloop。所以如果后面没有runloop的调用  这个延迟方法也是不会执行的。

   [self performSelector:@selector(performClicked) withObject:nil afterDelay:1];

// 老师注解:GCD维护的线程池默认是没有RunLoop的,runLoop的创建是调用currentRunLoop方法的时候系统内部实现会检查如果没有runLoop会创建一个返回给调用方。
    NSRunLoop * runLoop = [NSRunLoop currentRunLoop];

// 老师注解:这个地方调用了run,由于上面有添加Soure/Timer/Port,loop可以被卡住,当前线程会进入休眠状态,等待唤醒。这个地方为啥能从用户态切换到内核态,可以自行看runloop的源码逻辑,这里不再展开
   [runLoop run];

// 老师注解:你可以自己测试补充下面的log日志是不会运行的。也就是runLoop的run方法运行后处于休眠状态等待唤醒,1秒延迟执行的的方法会唤醒该线程 调用你的分派方法,执行完了之后,run方法会退出,继续执行下面老师补充的打印方法end

NSLog(@"end");

});

一般业务中几乎没有场景和同学会这样使用,全局并发队列是大家可共享访问的,另外如果需要操作runloop一般可以和NSThread 配套使用。


由以上分析就很好解释你上面代码的问题了

dispatch_async(dispatch_get_global_queue(0, 0), ^{
   NSLog(@"进入异步线程");

// 当前runloop

   NSRunLoop * runLoop = [NSRunLoop currentRunLoop];

// 因为没有事件源,也就意味着卡不住runloop,直接执行后面的逻辑
   [runLoop run];

// 分派的延迟方法无法获得执行
   [self performSelector:@selector(performClicked) withObject:nil afterDelay:1];
   
});





1 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信