当 NSOperationQueue 完成所有任务时获取通知
NSOperationQueue
有 waitUntilAllOperationsAreFinished
,但我不想同步等待它。 我只想在队列完成时隐藏用户界面中的进度指示器。
实现这一目标的最佳方法是什么?
我无法从我的 NSOperation
发送通知,因为我不知道哪一个将是最后一个,并且 [queue actions]
可能还不为空(或者更糟 - 重新填充)收到通知时。
NSOperationQueue
has waitUntilAllOperationsAreFinished
, but I don't want to wait synchronously for it. I just want to hide progress indicator in UI when queue finishes.
What's the best way to accomplish this?
I can't send notifications from my NSOperation
s, because I don't know which one is going to be last, and [queue operations]
might not be empty yet (or worse - repopulated) when notification is received.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
使用 KVO 观察队列的
operations
属性,然后您可以通过检查[queue.operations count] == 0
来判断队列是否已完成。在您执行 KVO 的文件中的某个位置,为 KVO 声明一个上下文,如下所示 (更多信息):
当您设置队列时,请执行以下操作:
然后在您的
observeValueForKeyPath
中执行此操作:(假设您的
NSOperationQueue
位于名为queue
的属性中)在对象完全释放之前的某个时刻(或者当它停止关心队列状态时),您需要像这样从 KVO 取消注册:
附录:iOS 4.0 有一个
NSOperationQueue.operationCount
属性,根据文档,该属性是 KVO 兼容的。 然而,这个答案在 iOS 4.0 中仍然有效,因此它对于向后兼容性仍然有用。Use KVO to observe the
operations
property of your queue, then you can tell if your queue has completed by checking for[queue.operations count] == 0
.Somewhere in the file you're doing the KVO in, declare a context for KVO like this (more info):
When you setup your queue, do this:
Then do this in your
observeValueForKeyPath
:(This is assuming that your
NSOperationQueue
is in a property namedqueue
)At some point before your object fully deallocs (or when it stops caring about the queue state), you'll need to unregister from KVO like this:
Addendum: iOS 4.0 has an
NSOperationQueue.operationCount
property, which according to the docs is KVO compliant. This answer will still work in iOS 4.0 however, so it's still useful for backwards compatibility.如果您期望(或希望)某些与此行为匹配的内容:
您应该注意,如果将许多“短”操作添加到队列中,您可能会看到此行为(因为操作是作为添加到队列的一部分而启动的)队列):
在我的项目中,我需要知道最后一个操作何时完成,在将大量操作添加到串行 NSOperationQueue(即 maxConcurrentOperationCount=1)之后,并且仅当它们全部完成时。
谷歌搜索我发现了一位苹果开发人员在回答“是串行 NSoperationQueue FIFO 吗?”这个问题时的声明。 --
在我的例子中,可以知道最后一个操作何时添加到队列中。 因此,在添加最后一个操作后,我向队列中添加另一个优先级较低的操作,该操作除了发送队列已清空的通知之外什么也不做。 根据苹果的声明,这可以确保仅在所有操作完成后才发送单个通知。
如果以不允许检测最后一个操作的方式添加操作(即非确定性),那么我认为您必须采用上面提到的 KVO 方法,并添加额外的保护逻辑来尝试检测是否进一步可以添加操作。
:)
If you are expecting (or desiring) something that matches this behavior:
You should be aware that if a number of "short" operations are being added to a queue you may see this behavior instead (because operations are started as part of being added to the queue):
In my project I needed to know when the last operation completed, after a large number of operations had been added to a serial NSOperationQueue (ie, maxConcurrentOperationCount=1) and only when they had all completed.
Googling I found this statement from an Apple developer in response to the question "is a serial NSoperationQueue FIFO?" --
In my case it is possible to know when the last operation was added to the queue. So after the last operation is added, I add another operation to the queue, of lower priority, which does nothing but send the notification that the queue had been emptied. Given Apple's statement, this ensures that only a single notice is sent only after all operations have been completed.
If operations are being added in a manner which doesn't allow detecting the last one, (ie, non-deterministic) then I think you have to go with the KVO approaches mentioned above, with additional guard logic added to try to detect if further operations may be added.
:)
添加一个依赖于所有其他操作的 NSOperation 以便它最后运行怎么样?
How about adding an NSOperation that is dependent on all others so it will run last?
一种替代方法是使用 GCD。 请参阅此 作为参考。
One alternative is to use GCD. Refer to this as reference.
从 iOS 13.0 开始,operationCount和 operation 属性已弃用。 您可以自己跟踪队列中的操作数量,并在所有操作完成后发出通知,这也同样简单。 此示例也适用于 Operation 的异步子类化。
下面是用于简单异步操作的Operation的子类
}
As of iOS 13.0, the operationCount and operation properties are deprecated. It's just as simple to keep track of the number of operations in your queue yourself and fire off a Notification when they've all completed. This example works with an asynchronous subclassing of Operation too.
Below is a subclass of Operation for easy asynchronous operations
}
我就是这样做的。
设置队列,并注册操作属性中的更改:
...观察者(在本例中为
self
)实现:在此示例中,“spinner”是一个
UIActivityIndicatorView
表明某事正在发生。 显然你可以改变以适应...This is how I do it.
Set up the queue, and register for changes in the operations property:
...and the observer (in this case
self
) implements:In this example "spinner" is a
UIActivityIndicatorView
showing that something is happening. Obviously you can change to suit...我正在使用一个类别来执行此操作。
NSOperationQueue+Completion.h
NSOperationQueue+Completion.m
用法:
来源:https://gist.github.com/artemstepanenko/7620471
I'm using a category to do this.
NSOperationQueue+Completion.h
NSOperationQueue+Completion.m
Usage:
Source: https://gist.github.com/artemstepanenko/7620471
使用 KVO 来观察队列的
operationCount
属性怎么样? 然后,当队列变空时,以及当队列不再空时,您会听到它。 处理进度指示器可能就像执行以下操作一样简单:What about using KVO to observe the
operationCount
property of the queue? Then you'd hear about it when the queue went to empty, and also when it stopped being empty. Dealing with the progress indicator might be as simple as just doing something like:添加最后一个操作,例如:
所以:
Add the last operation like:
So:
使用 ReactiveObjC 我发现这很好用:
With ReactiveObjC I find this works nicely:
仅供参考,您可以使用 swift 3 中的 GCD dispatch_group 来实现此目的。 所有任务完成后您都会收到通知。
FYI,You can achieve this with GCD dispatch_group in swift 3. You can get notified when all tasks are finished.
从 iOS 13 开始,您可以使用 https://developer.apple.com/documentation /foundation/operationqueue/3172534-addbarrierblock
From iOS 13, you can use https://developer.apple.com/documentation/foundation/operationqueue/3172534-addbarrierblock
您可以创建一个新的 NSThread,或在后台执行选择器,然后在那里等待。 当 NSOperationQueue 完成时,您可以发送自己的通知。
我在想这样的事情:
You can create a new
NSThread
, or execute a selector in background, and wait in there. When theNSOperationQueue
finishes, you can send a notification of your own.I'm thinking on something like:
如果您使用此 Operation 作为基类,您可以传递
whenEmpty {}< /code> 块到 OperationQueue:
If you use this Operation as your base class, you could pass
whenEmpty {}
block to the OperationQueue:没有KVO
Without KVO
如果你来这里寻找组合的解决方案 - 我最终只是听我自己的状态对象。
If you got here looking for a solution with combine - I ended up just listening to my own state object.