我试图建立一个批量图像下载器,在那里图像可以添加到一个队列的飞行下载,我可以找出进度和当他们完成下载。
通过我的阅读,似乎NSOperationQueue
用于队列功能,NSURLSession
用于网络功能似乎是我最好的选择,但我对如何串联使用这两个功能感到困惑。
我知道我把NSOperation
的示例添加到NSOperationQueue
中,它们会排队,而且好像我用NSURLSessionDownloadTask
创建了一个下载任务,如果我需要多个任务,我会用multiple,但是我不确定我是如何把这两个任务放在一起的。NSURLSessionDownloadTaskDelegate
似乎拥有下载进度和完成通知所需的所有信息,但我还需要能够停止特定的下载,停止所有的下载,并处理我从下载中返回的数据。
7条答案
按热度按时间nszi6y051#
您的直觉是正确的。如果发出许多请求,则
NSOperationQueue
的值为4或5会非常有用。如果没有这样的值,则如果发出许多请求(例如,50个大图像),则在慢速网络连接下工作时可能会遇到超时问题操作队列也具有其他优点(例如依赖性、分配优先级等),但是控制并发程度是关键的好处,恕我直言。如果您使用的是基于
completionHandler
的请求,那么实现基于操作的解决方案就非常简单(这是典型的并发NSOperation
子类实现;有关详细信息,请参阅 * 并发编程指南 * 的“操作队列”一章中的 * 配置并发执行的操作 * 部分)。如果您使用的是基于
delegate
的实现,那么事情很快就会变得非常棘手,这是因为NSURLSession
有一个可以理解(但非常烦人)的特性,即任务级委托是在会话级实现的。两个需要不同处理的不同请求调用共享会话对象上的同一个委托方法。可以在操作中 Package 基于委托的
NSURLSessionTask
(我和其他人肯定已经做过了),但它涉及一个笨拙的过程,让会话对象维护一个交叉引用任务标识符和任务操作对象的字典,让它将这些任务委托方法传递给任务对象,然后让任务对象符合各种NSURLSessionTask
委托协议,这是一项相当大的工作量,因为NSURLSession
在会话上不提供maxConcurrentOperationCount
风格的特性(更不用说NSOperationQueue
的其他优点了,比如依赖项、完成块等等)。值得指出的是,基于操作的实现在后台会话中是不太好用的。在应用程序终止后,您的上传/下载任务将继续正常运行(这是一件好事,这是后台请求中相当重要的行为),但当您的应用重新启动时,操作队列和它的所有操作都消失了,所以你必须使用一个纯粹的基于代理的
NSURLSession
实现来进行后台会话。pvcm50d12#
从概念上讲,NSURLSession是一个操作队列。如果在完成处理程序上恢复NSURLSession任务和断点,堆栈跟踪可能会非常明显。
下面是Ray Wenderlich关于NSURLSession的教程的摘录,其中添加了一条
NSLog
语句,用于在执行完成处理程序时创建断点:在上面,我们可以看到完成处理程序正在
Thread 5 Queue: NSOperationQueue Serial Queue
中执行。因此,我的猜测是每个NSURLSession维护它自己的操作队列,并且添加到会话的每个任务都作为NSOperation执行,因此,维护控制NSURLSession对象或NSURLSession任务的操作队列没有意义。
NSURLSessionTask本身已经提供了等效的方法,如
cancel
、resume
、suspend
等。的确,它比您自己的NSOperationQueue具有更少的控制权,但是,NSURLSession是一个新类,其目的无疑是减轻您的负担。
z0qdvdin3#
executing
和finishing
属性保存有关当前NSOperation
状态的信息。一旦finishing
设置为YES
,executing
设置为NO
,您的操作就被视为已完成。正确的处理方法不需要dispatch_group
,可以简单地编写为异步NSOperation
:术语
asynchronous
具有很大的误导性,它并不是指UI(主)线程和后台线程之间的区别。如果
isAsynchronous
被设置为YES
,则意味着代码的某些部分相对于main
方法异步执行。* * 在main
方法内部进行异步调用,并且该方法将在主方法完成后完成**。我有一些幻灯片是关于如何在苹果操作系统上处理并发的:https://speakerdeck.com/yageek/concurrency-on-darwin.
dispatch_group_t
。你可以把它们当作GCD的保留计数器。想象一下
NSOperation
子类的main
方法中的以下代码:bhmjp9jg4#
使用NSURLSession,你不用手动向队列添加任何操作,你可以使用NSURLSession上的
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
方法生成一个数据任务,然后启动(通过调用resume方法)。您可以提供操作队列,以便控制队列的属性,如果需要,还可以将其用于其他操作。
要对数据任务执行的NSOperation执行的任何常规操作(即启动、暂停、停止、恢复)。
要排队下载50个图像,您只需创建50个NSURLSession将正确排队的数据任务。
20jt8wwn5#
如果您正在使用OperationQueue,并且不希望每个操作创建许多并发网络请求,则只需在将每个操作添加到队列后调用queue.waitUntilAllOperationsAreFinished()即可。现在,这些操作将仅在前一个操作完成后执行,从而显著减少并发网络连接的数量。
ar7v8xwq6#
下面是一个将NSOperation与NSURLSession结合使用的示例项目:https://github.com/MacMark/Operations-Demo
对于后台会话,您可以通过在此回调中使用会话的标识符来恢复NSOperation:
5n0oy7gb7#
也许你正在寻找这个:
http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
有点奇怪的是,这不是“内置的”,但是如果你想把NSURL的东西和NSOperation的东西挂起来,看起来你必须在主线程中重用runloop,并使操作成为一个“并发的”操作(“并发的”到队列)。
尽管在您的情况下--如果只是简单的下载,没有后续的、依赖的操作连接--我不确定使用NSOperation会得到什么。