4

我刚开始使用 AFNetworking,我正在尝试学习如何正确使用它。我将其子类化并使用正确的基本 URLAFHTTPClient创建了我自己的。 我正在使用 HTTP POST 请求与我的服务器进行通信,并使用 xml 进行服务器响应。MyAppClient

为了发送请求,我这样做:

    [[MyAppClient sharedClient] postPath:somePath parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {

    // need to parse the data here...

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    //
    NSLog(@"%@", [error localizedDescription]);
}];  

几个问题:

  1. AFHTTPClient如果无论如何它使用NSURLConnection不阻塞主线程 的异步操作,为什么还要使用操作?

  2. 在获得需要解析的数据后,我现在是否应该创建一个新操作来解析数据?
    在我看来,在操作中也解析数据然后返回解析的对象会更好吗?

  3. 在同一主题中,我有一个自定义的通用 XMLParser 类,它获取 aNSData并将其解析为NSDictionary,并且我想将它用于所有响应,如何将它集成到中AFHTTPClient AFHTTPRequestOperation以便响应已经被解析?

4

3 回答 3

2

如果 AFHTTPClient 使用不阻塞主线程的异步 NSURLConnection ,为什么还要使用操作?

这实际上是一个很好的问题。

事实上,一个可行的“HTTPRequestOperation”类并不都需要从NSOperation. 的设计AFHTTPRequestOperation很可能是基于苹果工程师“Quinn”介绍的“原始”设计,他与他的班级一起发明了第一个“参考设计”,QHTTPOperation并提供了许多宝贵的样品——这些样品仍然被强烈推荐和值得去看一眼。这第一个设计子类 aNSOperation并封装了一个NSURLConnection对象。

这种设计有很多优点:

  • 由于它是 的子类NSOperation因此网络请求看起来像一个“异步操作”。这基本上意味着,网络请求具有主要方法startcancel并且具有完成处理程序来指示请求的最终结果。这个通用API 对于异步网络操作很重要,因此它成为更通用的异步操作

  • 由于它是一个类,它封装了请求的所有相关状态变量。例如,请求、响应、响应数据、错误(如果有)和一些更相关的状态变量。然后,“网络请求对象”变得非常方便使用,不像委托方法,当一个委托对象的委托方法中应该处理多个请求时,它开始变得困难。

  • 一个NSOperation对象可以排队到一个NSOperationQueue. 这样就可以定义请求的顺序,特别是任何其他操作,以及同时活动操作(请求)的数量(如果您有很多)。

  • 可以在其他操作之间NSOperation定义或多或少复杂的依赖关系,这使您可以添加一些额外的“业务逻辑”层。有时,这对于解决更复杂的异步问题变得非常方便。

所以,为什么已经异步NSURLConnection被封装在一个子类中的问题NSOperation是这些前面提到的优点。原因是永远不要将它像同步函数一样包装到 anNSOperation中,以便它可以在 a 中执行NSOperationQueue

事实上,对此存在广泛的误解。看来,很多人认为网络请求操作的方法会在执行上下文中执行NSOperation(例如添加到一个NSOperationQueue时)。但是,情况并非如此(在各种其他实现中可能存在一些小例外)。方法的执行上下文(主要是 的委托方法NSULRConnection)是一个专用的私有线程,将由NSOperation子类创建。不管怎样,底层的低层函数NSURLConnection也会在它们的私有执行上下文(一个或多个线程)上执行。

只有start方法会在操作的执行上下文中执行,它会快速返回。也就是说,如果有一个队列(比如调度队列或 NSOperationQueue)在其中调度了操作,那么只有该start方法在队列的执行上下文上执行。

然而,NSOperationisFinished状态将被推迟到网络请求确实完成的点。此状态对其他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 解析器操作。(不过,对于这种依赖关系还有其他更简单的解决方案)

于 2013-10-03T21:39:29.843 回答
0
  1. 这没有立即意义。我的猜测是使用标准机制可以提供最佳性能。但是,成功/失败块也在操作中执行。

  2. 我在操作的成功块中进行所有解析。如果您使用 JSON,您还可以将 AFNetworking 配置为自动为您进行反序列化。不过,您可能希望将这些字典和数组转换为更智能的类。

  3. 看看AFJSONRequestOperation。它可能会给你一些提示。

于 2013-02-24T18:42:29.150 回答
0

1) 在 AFNetworking - 操作是最细粒度的级别。您可以启动它或将它们加入队列。如果您正在排队请求,AFHTTPClient 非常棒。看enqueueOperation

2) AFNetworking 保持模块化。本质上,您与他们的解析器无关。您可以使用任何 xml 解析器来解析数据。虽然我喜欢 (DCKeyValue)[https://github.com/dchohfi/KeyValueObjectMapping] 来解析您的数据并将它们直接转换为对象。

3)您不能像 RestKit 那样自动解析,但答案 2 应该对您有所帮助。

于 2013-10-03T17:57:02.260 回答