- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我最近遇到了延迟选择器没有触发的问题(一个 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/
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, over
我在这段代码中使用 performSelector 方法时遇到了一些问题: 这个方法在另一个名为“JSONMethods”的类中: +(void)sendPostMsgWithMultipleArgu
我有一个按钮,如果密码正确,我想在触发 segue 之前使用密码实现。当您输入错误的密码时,一切看起来都很好,我已经实现了另一个alertView来告诉用户密码是错误的。 当警报 View 弹出并在延
我正在使用 ReactiveCocoa 2.5,因为我需要支持 iOS 7。我是 ReactiveCocoa 的新手。我有这个代码: __weak typeof(self) weakSelf =
此代码有效,并且调用了 postSpamListUpdatedNotification - (void) postSpamListUpdatedNotification { [NIDPriva
如题。调用 performSelector:withObject:afterDelay 后需要调用 NSAutoReleasePool 吗? 我觉得performSelector:withObject
我在 uiview 子类中使用以下方法: [self performSelector:@selector(timeout) withObject:nil afterDelay:20]; 该方法按预期在
我使用以下代码在 4 秒延迟后开始重复 NSTimer: - (void)viewDidLoad { [self performSelector:@selector(startTimer) w
我有一个 View Controller ,它调用performSelector:withObject:afterDelay。但是,如果我在调用此方法后立即删除该 View Controller ,那
我有一个 NSSlider 对象(连续模式开启),它连接到 socket 方法 - (IBAction)UpdateValueFromSlider:(id)sender { [self per
performSelectorInBackground:中有performSelector: afterDelay:和NSObject方法。如何将它们合并为一行代码? 也许以某种方式与NSTimer在
我已经设置了一个块以在不同的队列上运行,并在延迟后调用另一个方法: piemanQ = dispatch_queue_create(PIEMAN_QUEUE_NAME, NULL); dispatch
我正在编写一个带有 slider 的游戏。为了从解决状态开始随机播放游戏,我想定期重复调用 pushRandomPiece 以直观地随机播放游戏。 我一开始想使用 dispatch_after 但我对
我想在后台线程中运行一个方法,第一个方法将在几秒钟后在同一(后台)线程上运行另一个方法。我写了这个: - (IBAction)lauch:(id)sender { [self performS
我在释放一个对象时遇到了 EXC_BAD_ACCESS,该对象具有很少的 performSelector:withObject:afterDelay,其中选择器方法正在调用另一个对象,而我正在释放该对
这个问题在这里已经有了答案: dispatch_after - GCD in Swift? (26 个回答) 关闭8年前。 我有一个 Objective-C 中的应用程序,我正在过渡到 Swift。在
我的问题是,在我的应用程序中的某个时刻,我调用 [performSelector: withObject: afterDelay:] 但在长达 1 秒的延迟期间,会发生一些事情来决定是否延迟方法应该或
我觉得我应该知道这一点,但我已经被难住了好几个小时,而且我已经没有想法了。 原理很简单,用户使用捏合操作来操纵 ScrollView 中的缩放和定位。如果他们按住捏的时间很短,则 ScrollView
我正在一个方法中创建一个 NSArray,所以当我完成它时我必须放弃它。我将此数组传递给 - (void)performSelector:(SEL)aSelector withObject:(id)a
要每x秒重复一次方法调用(或消息发送,我猜合适的术语是),最好使用NSTimer(NSTimer的scheduledTimerWithTimeInterval:target:selector:user
我是一名优秀的程序员,十分优秀!