gpt4 book ai didi

ios - NSInvocationOperation 回调太快

转载 作者:可可西里 更新时间:2023-11-01 04:47:51 26 4
gpt4 key购买 nike

我知道类似的问题已被问过几次,但我正在努力了解如何解决这个特定问题。到目前为止,我所做的一切都是在主踏板上进行的。我现在发现我需要执行一个需要一些时间的操作,我想在操作期间向我的显示器添加一个 HUD,并在操作完成时将其淡出。

在阅读了很多关于 GCD 的内容(并且变得很困惑)之后,我决定最简单的方法是使用 NSInvocationOperation 调用我的耗时方法并将其添加到新创建的 NSOperationQueue 中。这是我的:

        [self showLoadingConfirmation]; // puts HUD on screen

// this bit takes a while to draw a large number of dots on a MKMapView
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(timeConsumingOperation:)
object:[self lotsOfDataFromManagedObject]];

// this fades the HUD away and removes it from the superview
[operation setCompletionBlock:^{ [self performSelectorOnMainThread:@selector(fadeConfirmation:) withObject:loadingView waitUntilDone:YES]; }];

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperation:operation];

我希望这会显示 HUD,开始在 map 上绘制点,然后一旦该操作完成,淡出 HUD。

相反,它显示 HUD,开始在 map 上绘制点,然后在绘制点的同时逐渐淡出 HUD。根据我的 NSLogs,在调用淡出 HUD 的方法之前大约有四分之一秒的延迟。与此同时,点的绘制又持续了几秒钟。

我该怎么做才能让它等到 map 上的绘图完成后再淡出 HUD?

谢谢

编辑添加:

在进行以下更改后,我即将获得成功:

        NSInvocationOperation *showHud = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(showLoadingConfirmation)
object:nil];

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(timeConsumingOperation:)
object:[self lotsOfDataFromManagedObject]];

NSInvocationOperation *hideHud = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(fadeConfirmation:)
object:loadingView];

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];

NSArray *operations = [NSArray arrayWithObjects:showHud, operation, hideHud, nil];
[operationQueue addOperations:operations waitUntilFinished:YES];

奇怪,好像是先调用timeConsumingOperation,然后是showLoadingConfirmation,然后是fadeConfirmation。这是根据我的 NSLogs 得出的,这些方法在这些方法中触发。

我在屏幕上看到的行为是这样的:点被绘制并且 map 相应地调整它的缩放(timeConsumingOperation 的一部分),然后 HUD 出现在屏幕上,然后什么都没有。所有三个 NSLog 都会立即出现,即使 showLoadingConfirmation 在 timeConsumingOperation 完成之前不会发生并且 fadeConfirmation 似乎根本不会发生。

这看起来很奇怪,但也似乎暗示有一种方法可以让某些事情在 timeConsumingOperation 完成时发生。

我尝试添加这个:

[operationQueue setMaxConcurrentOperationCount:1];

还有这个:

[showHud setQueuePriority:NSOperationQueuePriorityVeryHigh];
[operation setQueuePriority:NSOperationQueuePriorityNormal];
[hideHud setQueuePriority:NSOperationQueuePriorityVeryLow];

但它们似乎没有任何区别。

最佳答案

在为 NSInvocationOperation 设置完成处理程序时,请注意您实际在做什么:当此类操作完成时,将发生以下情况(来自 NSOperation 类引用):

The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it. For example, if you have a custom thread for coordinating the completion of the operation, you could use the completion block to ping that thread.

所以首先,该 block 在辅助线程上执行(因此它将进入该线程的队列,当最终轮到它时,它只是将另一个作业发送到主线程的队列)。这意味着它会在这样的队列中与其他待处理的作业混合在一起,例如从您的 timeConsumingOperation: 选择器发送到主队列的引脚的最后更新。

问题来了:如果你不为不同的作业设置优先级,就没有办法告诉这些作业最终处理的顺序,即使你知道它们之前及时发送 。此外,在您的情况下,您的 NSInvocationOperation 已完成这一事实并不一定意味着在调用该 block 时所有对象都已在屏幕上绘制它仅意味着它们已被发送到轮到他们时要处理的 UI 更新线程。

考虑到这一点,并且考虑到您不想采用 GCD 方式,(我建议您再试一次,因为我知道这在开始时并不容易,但是当您开始使用它时,您会意识到它是对于几乎所有你想在 iPhone 上做的多线程事情来说,这是一个很好的解决方案)我会创建一个 NSOperationQueue 并将所有的工作发送到那里(一个删除 HUD 的工作,但优先级低于其他工作)。通过这种方式,您可以确保在完成所有“固定”作业后在主队列中处理 HUD 的移除,这是您的第一个目标。

关于ios - NSInvocationOperation 回调太快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13415957/

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