NSInvocationOperation回调太快了

时间:2012-11-16 11:45:26

标签: ios nsoperation nsoperationqueue nsinvocation nsinvocationoperation

我知道有几次问过类似的问题,但是我很难理解这个问题是如何解决的。到目前为止,我所做的一切都是在主要方面进行的。我现在发现我需要执行一个需要一些时间的操作,并且我希望在操作期间将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,开始在地图上绘制点,然后一旦操作完成,就会消除HUD。

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

我可以做些什么让它等到地图上的绘图完成后才会消失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,在这些方法中解雇。

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

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

我尝试添加这个:

[operationQueue setMaxConcurrentOperationCount:1];

还有这个:

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

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

2 个答案:

答案 0 :(得分:1)

在为NSInvocationOperation设置完成处理程序时,请注意您实际执行的操作:当此类操作完成时,会发生以下情况(来自NSOperation类参考):

  

无法保证完成块的确切执行上下文,但通常是辅助线程。因此,你应该   不要使用此块来执行任何需要非常具体的工作   执行上下文。相反,你应该将这项工作分流给你   应用程序的主线程或能够执行的特定线程   正在做。例如,如果您有一个用于协调的自定义线程   完成操作后,可以使用完成块来   ping那个帖子。

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

问题出现了:如果您没有为不同的工作设置优先级,即使您知道它们是在时间之前发送的,也无法告诉最终处理这些工作的顺序< / strong>即可。此外,在您的情况下,您的NSInvocationOperation已完成的事实并不一定意味着在调用块时已在屏幕上绘制了所有对象它仅表示它们已被发送到UI更新线程在轮到他们时进行处理。

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

答案 1 :(得分:1)

如果HUD消失,则调用完成块,这意味着返回了timeConsumingOperation:方法。

如果您仍然看到正在绘制点,这意味着即使在timeConsumingOperation:返回后,仍有动画或绘图事务仍在进行中或仍在排队。解决方案取决于您用于绘图的技术。你在使用核心动画吗?带注释的MapKit?