Ios 块未运行后的调度\u 请考虑这个简单的例子: - (void)viewDidLoad { [super viewDidLoad]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"BLOCK!!!"); }); while (YES) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; NSLog(@"RUN LOOP"); } }); }
在之后传递给Ios 块未运行后的调度\u 请考虑这个简单的例子: - (void)viewDidLoad { [super viewDidLoad]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"BLOCK!!!"); }); while (YES) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; NSLog(@"RUN LOOP"); } }); },ios,objective-c,grand-central-dispatch,nsrunloop,dispatch-after,Ios,Objective C,Grand Central Dispatch,Nsrunloop,Dispatch After,在之后传递给调度\u的第二次调用(3秒)的块未被激发。但是,如果我没有在(2秒)之后使用第一个调度_,那么它将按预期工作。为什么? 我知道,如果在内部运行nsrunlop的情况下删除while循环,则该循环可以正常工作,但我需要该循环我在示例中看不到任何已注册的输入源。我不认为分派算作输入源 在这种情况下,-runMode:beforeDate:将立即返回NO。您设置的无限循环只会旋转,而不会退出当前运行。它永远不会回到运行循环的顶部,也不会处理任何调度队列 在中,定义了behvior 讨论 如
调度\u的第二次调用(3秒)的块未被激发。但是,如果我没有在
(2秒)之后使用第一个调度_,那么它将按预期工作。为什么?
我知道,如果在内部运行nsrunlop
的情况下删除while循环,则该循环可以正常工作,但我需要该循环我在示例中看不到任何已注册的输入源。我不认为分派算作输入源
在这种情况下,-runMode:beforeDate:
将立即返回NO
。您设置的无限循环只会旋转,而不会退出当前运行。它永远不会回到运行循环的顶部,也不会处理任何调度队列
在中,定义了behvior
讨论
如果没有输入源或计时器连接到运行循环,则此方法立即退出并返回no;否则,它将在处理第一个输入源或到达limitDate后返回。手动从运行循环中删除所有已知的输入源和计时器并不保证运行循环将立即退出。macOS可以根据需要安装和删除其他输入源,以处理针对接收方线程的请求。因此,这些源可以阻止运行循环退出
你有密码吗
- 调度一个
dispatch\u在之后在主队列上运行;但是
- 使用重复调用
nsrunlop
的while
循环阻塞主队列
这只是阻止主线程执行非直接从主nsrunlop
调用的任何操作
此问题有三种解决方案:
您可以通过使用while
循环将代码分派到全局(即后台)队列来解决此问题:
这项技术是我们在GCD前的日子里所做的事情的一种排列。如今,这在很大程度上是无用的。这太没效率了
您可以使用从nsrunlop
调度并运行的NSTimer
,因此,当您仍然阻塞主队列时,至少会触发计时器
- (void)viewDidLoad{
[super viewDidLoad];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"OUTER");
[NSTimer scheduledTimerWithTimeInterval:3 repeats:false block:^(NSTimer * _Nonnull timer) {
NSLog(@"INNER!!!");
}];
while (true) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
});
}
这并不是问题的真正解决方案(您仍在阻止主线程从nsrunlop
本身运行之外的任何内容),但说明了runloop的本质
或者,显然,最好只删除while
循环:
- (void)viewDidLoad{
[super viewDidLoad];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"OUTER");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"INNER!!!");
});
});
}
底线是,现在,你几乎从不在线程(或其运行循环)上旋转。它的效率非常低,GCD提供了更优雅的方法来达到预期的效果。无限循环在这种方法中是个好主意吗?@trojanfoe什么好主意?如果我没有在之后使用第一个分派\u(同时仍在运行nsrunlopp),则会触发之后的第二个分派\u。如果我在之后再添加一级调度,为什么不触发呢?如果你想让这些东西正常工作,这是个好主意。在泵送runloop时,您还干扰了现有的runloop。移除循环,看看会发生什么。如果我移除循环,那么就没问题了,当然。我知道。但是我需要这个循环,我不明白为什么它会停止工作。你可能应该在你的问题中提到,因为它显然是罪魁祸首。它返回是,但不会立即返回。一旦到达日期,它将返回控件,但为什么不在不使用外部调度时阻止主线程呢?A处理线程上的事件,并且runMode:before:
也允许运行GCD块/项。但是GCD强制执行其串行队列的串行性质(主队列是串行队列),并且在之前调度的块完成之前,它不允许在该队列上运行任何东西(并且while
循环阻止了这一点)。现在我明白了。太明显了。谢谢
- (void)viewDidLoad{
[super viewDidLoad];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"OUTER");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"INNER!!!");
});
});
}