bee*_*eev 5 nsoperation nsoperationqueue nsinvocation ios 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];
Run Code Online (Sandbox Code Playgroud)
我希望这能显示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];
Run Code Online (Sandbox Code Playgroud)
奇怪的是,它似乎首先调用timeConsumingOperation,然后是showLoadingConfirmation,然后是fadeConfirmation.这是根据我的NSLogs,在这些方法中解雇.
我在屏幕上看到的行为是:绘制点并且地图相应地调整它的缩放(部分时间消耗操作),然后HUD出现在屏幕上,然后没有.所有三个NSLog都会立即出现,即使showLoadingConfirmation在timeConsumingOperation完成并且fadeConfirmation似乎根本没有发生时也不会发生.
这看起来很奇怪,但似乎也暗示有一种方法可以在完成timeConsumingOperation时发生一些事情.
我尝试添加这个:
[operationQueue setMaxConcurrentOperationCount:1];
Run Code Online (Sandbox Code Playgroud)
还有这个:
[showHud setQueuePriority:NSOperationQueuePriorityVeryHigh];
[operation setQueuePriority:NSOperationQueuePriorityNormal];
[hideHud setQueuePriority:NSOperationQueuePriorityVeryLow];
Run Code Online (Sandbox Code Playgroud)
但他们似乎没有任何区别.
在为 NSIncationOperation 设置完成处理程序时,请注意您实际在做什么:当此类操作完成时,会发生以下情况(来自 NSOperation 类参考):
\n\n\n\n\n无法保证完成块的确切执行上下文,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。相反,您应该将该工作分流到应用程序 xe2x80x99 的主线程或能够执行该操作的特定线程。例如,如果您有一个自定义线程来协调操作的完成,则可以使用完成块来 ping 该线程。
\n
因此,首先,该块在辅助线程上执行(因此它将进入该线程的队列,当最终轮到它时,它只是将另一个作业发送到主线程的队列)。这意味着它将与其他待处理作业混合在此类队列中,例如从选择器发送到主队列的引脚的最新更新timeConsumingOperation:。
那么问题来了:如果你不为不同的作业设置优先级,那么就没有办法知道这些作业最终被处理的顺序,即使你知道它们之前已经及时发送过。此外,在您的情况下,您的 NSInitationOperation 已完成这一事实并不一定意味着在调用该块时所有对象都已在屏幕上绘制,它仅意味着它们已被发送到 UI 更新线程以在以下情况下进行处理:轮到他们了。
\n\n考虑到这一点,并且考虑到您不想采用 GCD 方式(我建议再尝试一次,因为我知道一开始这并不容易,但当您接受它时,您会意识到这是一个很棒的解决方案对于您想在 iPhone 上执行的几乎所有多线程操作)我会创建一个 NSOperationQueue 并将所有作业发送到那里(包括删除 HUD 的作业,但优先级低于其他作业)。通过这种方式,您可以确保在所有“固定”作业完成后在主队列中处理 HUD 的删除,这是您的第一个目标。
\n| 归档时间: |
|
| 查看次数: |
448 次 |
| 最近记录: |