AFHTTPClient - 解析响应对象

时间:2012-07-06 16:01:24

标签: objective-c ios nsurlconnection nsxmlparser afnetworking

我刚刚开始使用AFNetworking,我正在努力学习如何正确地完成它。 我将AFHTTPClient子类化,并使用正确的基本URL创建了我自己的MyAppClient 我正在使用HTTP POST请求和服务器响应与xml进行通信。

用于发送请求:

    [[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类,它获取NSData并将其解析为NSDictionary,我想将它用于所有响应,怎么能我将其集成到AFHTTPClient AFHTTPRequestOperation中,以便已经解析了响应?

3 个答案:

答案 0 :(得分:2)

  

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

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

事实上,一个可行的" HTTPRequestOperation" class不是从NSOperation继承的所有类。 AFHTTPRequestOperation的设计很可能基于"原创"由Apple工程师" Quinn"介绍的设计,他发明了第一个"参考设计"与他的班级QHTTPOperation并提供了一些宝贵的样本 - 仍然强烈推荐,值得一看。第一个设计是NSOperation的子类,并封装了一个NSURLConnection对象。

这种设计有许多优点:

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

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

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

  • 使用NSOperation可以在其他操作中定义更多或更少的复杂依赖项,这样您就可以添加一些额外的"业务逻辑"。有时,这对于解决更复杂的异步问题变得非常方便。

因此,问题为什么已经异步NSURLConnection被封装在NSOperation的子类中是上述优点。原因是永远不要将它像同步函数一样包装到NSOperation中,以便它可以在NSOperationQueue中执行。

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

只有start方法将在操作的执行上下文中执行,后者会快速返回。也就是说,如果存在已调度操作的队列(比如调度队列或NSOperationQueue),则只有start方法在队列的执行上下文中执行。

然而,NSOperation的{​​{1}}状态将被推迟到网络请求确实完成的时间点。此状态对于其他isFinished对象和NSOperation具有重要意义:它表示此请求已完成的队列和其他操作。

因此,NSOperationQueue不是定义网络请求功能的执行上下文的工具,而是组织和设置与其他操作的关系的手段。


  

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

好吧,你可以这样做。但是,我不认为这是一个好的设计决策:操作应该只处理特定的任务。网络操作是一个,解析任务_是另一个任务,也可以是一个操作。

这样做的一个原因是操作可以被分类"关于他们主要需要哪些系统资源:CPU,内存,IO等。合并不同的"任务类型"因此无法利用它们将它们与专用队列相关联以控制系统资源的利用率(见下文)。

当然,你可以将解析任务作为一项操作。这是否有意义,取决于:

是否要将特定任务(或函数)设为NSOperation的决定取决于以下注意事项:

  • "操作"是否合理,如果该任务可能需要很长时间才能完成(从用户的角度来看),因此您(作为开发人员)希望用户有机会取消任务:(您还记得:异步操作有主要方法NSOperation

  • 另一个原因是将操作与特定的执行上下文相关联,后者本身与特定的共享和有限的系统资源相关联 - 如CPU,内存,IO等。这使您可以控制例如并行数执行需要特定系统资源的操作。说,你有一个"磁盘绑定"任务。在这种情况下,您可以创建一个cancel,其并发操作数为1,并为其提供特定的"角色"和一个合适的名称,例如" DiskBoundQueue"。该队列可帮助您控制创建和操作的开始,并强制限制并行执行操作的数量,以便限制系统资源不会耗尽。然后,人们会添加"磁盘绑定"仅对专用的" DiskBoundQueue"进行操作。由于磁盘在同时从不同任务访问时运行次优,因此并发操作数设置为1.也就是说,此类专用队列有助于优化系统资源的利用率。

  • 如果操作之间存在依赖关系,则表示只有在操作A AND操作B成功完成时才要启动操作C. NSOperationQueue提供了建立此类依赖关系的方法。

  • 另一个原因可能是控制对共享资源的并发访问:如果有多个操作访问添加到串行NSOperation的某个共享资源(例如,ivar),则访问权限共享资源是序列化的,因此"线程安全"。但是,如果并发是唯一的要求,我宁愿使用更简单的方法来利用调度队列和块。

所以,为了更准确地对待你的问题:不,NSOperationQueue可能会超大。您可能更好地使用专用的调度队列,可能是一个也可以解决共享资源并发访问的串行队列。


  

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

一种可行的方法就是在NSOperation或AFClient的完成处理程序中启动XML解析器。

如果你有另一个依赖于XML解析器结果的操作,那么一种方法是将XML解析器封装在AFHTTPRequestOperation中,然后制作另一个操作依赖于XML解析器操作。 (尽管如此,还有其他更简单的解决方案)

答案 1 :(得分:0)

  1. 这不会立即有意义。我的猜测是使用标准机制可以提供最佳性能。但是,成功/失败块也会在操作中执行。

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

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

答案 2 :(得分:0)

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

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

3)你不能像RestKit那样自动解析,但是答案2可以帮助你。