如果 AFHTTPClient 使用不阻塞主线程的异步 NSURLConnection ,为什么还要使用操作?
这实际上是一个很好的问题。
事实上,一个可行的“HTTPRequestOperation”类并不都需要从NSOperation
. 的设计AFHTTPRequestOperation
很可能是基于苹果工程师“Quinn”介绍的“原始”设计,他与他的班级一起发明了第一个“参考设计”,QHTTPOperation
并提供了许多宝贵的样品——这些样品仍然被强烈推荐和值得去看一眼。这第一个设计子类 aNSOperation
并封装了一个NSURLConnection
对象。
这种设计有很多优点:
由于它是 的子类,NSOperation
因此网络请求看起来像一个“异步操作”。这基本上意味着,网络请求具有主要方法start
,cancel
并且具有完成处理程序来指示请求的最终结果。这个通用API 对于异步网络操作很重要,因此它成为更通用的异步操作。
由于它是一个类,它封装了请求的所有相关状态变量。例如,请求、响应、响应数据、错误(如果有)和一些更相关的状态变量。然后,“网络请求对象”变得非常方便使用,不像委托方法,当一个委托对象的委托方法中应该处理多个请求时,它开始变得困难。
一个NSOperation
对象可以排队到一个NSOperationQueue
. 这样就可以定义请求的顺序,特别是任何其他操作,以及同时活动操作(请求)的数量(如果您有很多)。
可以在其他操作之间NSOperation
定义或多或少复杂的依赖关系,这使您可以添加一些额外的“业务逻辑”层。有时,这对于解决更复杂的异步问题变得非常方便。
所以,为什么已经异步NSURLConnection
被封装在一个子类中的问题NSOperation
是这些前面提到的优点。原因是永远不要将它像同步函数一样包装到 anNSOperation
中,以便它可以在 a 中执行NSOperationQueue
。
事实上,对此存在广泛的误解。看来,很多人认为网络请求操作的方法会在执行上下文中执行NSOperation
(例如添加到一个NSOperationQueue时)。但是,情况并非如此(在各种其他实现中可能存在一些小例外)。方法的执行上下文(主要是 的委托方法NSULRConnection
)是一个专用的私有线程,将由NSOperation
子类创建。不管怎样,底层的低层函数NSURLConnection
也会在它们的私有执行上下文(一个或多个线程)上执行。
只有start
方法会在操作的执行上下文中执行,它会快速返回。也就是说,如果有一个队列(比如调度队列或 NSOperationQueue)在其中调度了操作,那么只有该start
方法在队列的执行上下文上执行。
然而,NSOperation
的isFinished
状态将被推迟到网络请求确实完成的点。此状态对其他NSOperation
对象和具有重要意义NSOperationQueue
:它向队列和其他操作发出此请求已完成的信号。
因此,NSOperation
它不是定义网络请求功能的执行上下文的工具,而是组织和设置与其他操作的关系的一种手段。
在获得需要解析的数据后,我现在是否应该创建一个新操作来解析数据?在我看来,在操作中也解析数据然后返回解析的对象会更好吗?
好吧,你可以这样做。但是,我不认为这是一个好的设计决策:一个操作应该只处理一个特定的任务。网络操作是一个,解析任务_是另一个任务,它也可以是一个操作。
原因之一是操作可以根据它们主要需要哪些系统资源进行“分类”:CPU、内存、IO 等。合并不同的“任务类型”使得无法利用将它们关联到专用队列以控制系统资源的利用(见下文)。
好吧,当然,您可以将解析任务作为操作。不过,这是否有意义,取决于:
是否要执行特定任务(或功能)的NSOperation
决定取决于以下考虑:
“操作”是合理的,如果该任务可能需要很长时间才能完成(从用户的角度来看),因此您(作为开发人员)希望用户有机会取消任务:(请记住:异步操作有主要方法cancel
)
另一个原因是将操作与特定的执行上下文相关联,该执行上下文本身与特定的共享和有限的系统资源相关联 - 例如 CPU、内存、IO 等。这使您可以控制例如需要特定的并行执行操作的数量系统资源。假设您有一个“磁盘绑定”任务。在这种情况下,您可以创建一个NSOperationQueue
其并发操作数为 1,并为其赋予特定的“角色”和合适的名称,例如“DiskBoundQueue”。队列帮助您控制操作的创建和启动,并强制限制并行执行操作的数量,以免耗尽受限的系统资源。然后,将“磁盘绑定”操作添加到专用的“DiskBoundQueue”。由于磁盘在同时从不同任务访问时运行不佳,因此将并发操作数设置为 1。也就是说,这种专用队列有助于优化系统资源的利用率。
如果您在操作之间存在依赖关系,假设您只想在操作 A AND 操作 B 已成功完成时才开始操作 C。NSOperation
提供一种建立这种依赖关系的方法。
另一个原因可能是控制对共享资源的并发访问:如果有几个访问某个共享资源(例如 ivar)的操作被添加到 serialNSOperationQueue
中,则对共享资源的访问被序列化,因此“线程安全” ”。但是,如果并发是唯一的要求,我更愿意使用更简单的方法,利用调度队列和块。
因此,为了更准确地了解您的问题:不, anNSOperation
可能会过大。您可能最好使用专用的调度队列,可能是一个串行的队列,它也可以解决共享资源的并发访问。
在同一主题上,我有一个自定义的通用 XMLParser 类,它获取 NSData 并将其解析为 NSDictionary,我想将它用于所有响应,如何将它集成到 AFHTTPClient AFHTTPRequestOperation 以便响应已经解析?
例如,一种可行的方法是在 aAFHTTPRequestOperation
或 AFClient 的完成处理程序中启动 XML 解析器。
如果您有另一个操作依赖于 XML 解析器的结果,那么一种方法是将 XML 解析器封装在一个NSOperation
中,然后使另一个操作依赖于 XML 解析器操作。(不过,对于这种依赖关系还有其他更简单的解决方案)