gpt4 book ai didi

ios - 哪个队列用于-[NSObject performSelector :withObject:afterDelay]?

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:00:36 27 4
gpt4 key购买 nike

我最近遇到了延迟选择器没有触发的问题(一个 NSTimer 和用 performSelector:withObject:afterDelay 调用的方法)。

我已经阅读了 Apple 的文档,它确实在特殊注意事项区域中提到了,

This method registers with the runloop of its current context, and depends on that runloop being run on a regular basis to perform correctly. One common context where you might call this method and end up registering with a runloop that is not automatically run on a regular basis is when being invoked by a dispatch queue. If you need this type of functionality when running on a dispatch queue, you should use dispatch_after and related methods to get the behavior you want.

这很有意义,除了当前上下文部分的运行循环。我发现自己对它实际上要去哪个运行循环感到困惑。是线程的主运行循环处理所有事件,还是在我们不知情的情况下是不同的运行循环?

例如,如果我在一个被称为 CoreAnimation 完成 block 的 block 中调用 performSelector 之前遇到断点,调试器会显示执行在主线程上。但是,调用 performSelector:withObject:afterDelay 从未实际运行选择器。这让我认为调用有效地注册了与 CoreAnimation 框架关联的运行循环,因此无论 performSelector 调用在主线程上执行,如果 CoreAnimation 不轮询其运行循环,操作不执行。

performSelectorOnMainThread:WithObject:waitUntilDone 替换该 block 内的调用可以解决问题,但我很难说服同事这是根本原因。

更新:我能够将问题的根源追溯到 UIScrollViewDelegate 回调。有意义的是,当调用 UI 委托(delegate)回调时,主运行循环将处于 UITrackingRunLoopMode 中。但此时,处理程序将在后台队列中排队一个 block ,然后执行将跳过其他几个队列,最终返回到主运行循环。问题是当它回到主运行循环时,它仍然处于 UITrackingRunLoopMode。我认为当委托(delegate)方法完成时,主运行循环应该已经退出 UITracking 模式,但是当执行回到主运行循环时,它仍然处于该模式。推迟从 UIScrollViewDelegate 方法启 Action 业后台排队的代码可以解决这个问题,例如.后台任务排回主线程时使用的runloop模式是否可能取决于runloop在后台任务排队时所处的模式?

从本质上讲,唯一的变化就是从这个开始......

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
// Currently in UITrackingRunLoopMode
dispatch_async(someGlobalQueue, someBlock);
// Block execution hops along other queues and eventually comes back to main runloop and will still be in tracking mode.
}

对此

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
// Currently in UITrackingRunLoopMode
[self performSelector:@selector(backQueueTask) withObject:nil afterDelay:0 inModes:@[NSDefaultRunLoopMode]];
}
-(void)backQueueTask {
// Currently in NSDefaultRunLoopMode
dispatch_async(someGlobalQueue, someBlock);
// Hops along other queues and eventually comes back to main runloop and will still be in NSDefaultRunLoopMode.
// It's as if the runloop mode when execution returns was dependent on what it was when the background block was queued.
}

最佳答案

每个线程只有一个运行循环,因此如果您在主线程上,那么您也处于主运行循环中。但是,运行循环可以以不同的模式运行。

您可以尝试一些事情来弄清问题的根源:

您可以使用 +[NSRunLoop currentRunLoop]+[NSRunLoop mainRunLoop] 来验证您是从主线程和主运行循环执行的。

您还可以将当前运行循环直接与 NSTimer 一起使用来安排延迟的执行选择器。例如:

void (^completionBlock)(BOOL) = ^(BOOL finished) {

NSCAssert([NSRunLoop currentRunLoop] == [NSRunLoop mainRunLoop], @"We're not on the main run loop");

NSRunLoop* runLoop = [NSRunLoop mainRunLoop];

// Immediate invocation.
[runLoop performSelector:@selector(someMethod) target:self argument:nil order:0 modes:@[NSDefaultRunLoopMode]];

// Delayed invocation.
NSTimer* timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(someMethod) userInfo:nil repeats:NO];
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];

};

这些调用本质上等同于 -performSelector:withObject:-performSelector:withObject:afterDelay:

这让您可以确认您使用的是哪个运行循环。如果您在主运行循环中并且延迟调用没有运行,则主运行循环可能在默认模式下不为计时器提供服务的模式下运行。例如,当 UIScrollView 正在跟踪触摸输入时可能会发生这种情况。

关于ios - 哪个队列用于-[NSObject performSelector :withObject:afterDelay]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31164184/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com