- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我知道类似的问题已被问过几次,但我正在努力了解如何解决这个特定问题。到目前为止,我所做的一切都是在主踏板上进行的。我现在发现我需要执行一个需要一些时间的操作,我想在操作期间向我的显示器添加一个 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/
我在操作里面取消一个NSInvocationOperation是不是对的?示例: .h文件: //defined in the interface NSInvocationOperation *op1
我知道类似的问题已被问过几次,但我正在努力了解如何解决这个特定问题。到目前为止,我所做的一切都是在主踏板上进行的。我现在发现我需要执行一个需要一些时间的操作,我想在操作期间向我的显示器添加一个 HUD
- (void)viewDidLoad { NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];
我已经在我的项目中编写了代码 [NSInvocationOperation alloc] initWithTarget:
我正在尝试使用 NSInvocationOperation 对一些 TWRequest 调用进行排队。它似乎以正确的顺序添加方法调用,但 doSomething: 方法几乎同时被调用,即并发运行,而不
我正在尝试创建 NSInvocationOperation 以便它应该使用参数调用对象的方法 - (void) getImages: (NSRange) bounds { NSOperatio
我有一个 NSInvocationOperation,它会在后台下载和解析一系列 NSXMLDocuments 以响应我的 UI。 我尝试停止调用操作是调用我的 NSOperationQueue 的
Objective-C/iOS 领域的新手。拥有 PHP 和 C++ 经验。 我在使用 NSInvocationOperation 时遇到了一些问题。这是我的情况: 借助一些在线帮助,我有一个类 ge
1) 当我们在 NSoperationQueue 中添加 NSOperation 或 NSInvocationOperation 时发生了什么? 2) NSoperation 和 NSInvocati
我正在将我制作的 Android 应用移植到 iOS。 Android 有一个 Yield() 函数可以将线程从运行中移到线程队列的后面(?)。这很有用,这样该线程就不会占用过多的 CPU 并使其他一
Foundation Framework 中共有三个操作类(NSOperation、NSInvocationOperation 和NSBlockOperation)。 我已经阅读了 concurren
我正在尝试将 NSOperation 对象放入 NSOperationQueue 中。但似乎我误解了如何正确初始化 NSInvocationOperation(一个似乎为我的目的量身定制的子类,因为我
我在 iOS5 中使用 NSInvocationOperation 和 NSOperationQueue 开发。根据关于调用对象的苹果文档: The NSInvocationOperation cla
我有一个相当简单但昂贵的任务需要在后台运行,这是标准的 NSOperation 情况。我还需要确保该操作支持取消并适当停止。鉴于该要求,哪种方法更好:只是将昂贵的方法调用包装在 NSInvocatio
我的代码突然无法在 Xcode 6.1 中编译(我确定它在 Xcode 6 GM 和 beta 版本中工作)。它显示错误消息: 'NSInvocationOperation' is unavailab
我试图让我的 UITableView 在浏览大约 700 张从 Internet 下载、缓存(到内部存储)并显示在表格的每个单元格上的图片时保持平滑。就滚动性能而言,我的代码到目前为止似乎还不错。但是
我是一名优秀的程序员,十分优秀!