【问题标题】:AFHTTPClient - Parsing response objectAFHTTPClient - 解析响应对象
【发布时间】:2012-07-07 02:56:44
【问题描述】:

我刚开始使用 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. 1234563 AFHTTPClient AFHTTPRequestOperation 以便已经解析响应?

【问题讨论】:

    标签: objective-c ios nsurlconnection nsxmlparser afnetworking


    【解决方案1】:

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

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

    事实上,一个可行的“HTTPRequestOperation”类并不是必须从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 方法会在队列的执行上下文中执行。

    NSOperationisFinished 状态将被推迟到网络请求确实完成的点。此状态对于其他NSOperation 对象和NSOperationQueue 具有重要意义:它向队列和其他操作发出此请求已完成的信号。

    因此,NSOperation 与其说是定义网络请求函数的执行上下文的工具,不如说是一种组织和设置与其他操作的关系的方法。


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

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

    其中一个原因是操作可以根据它们主要需要的系统资源进行“分类”:CPU、内存、IO 等。合并不同的“任务类型”使得无法利用将它们关联到专用队列以控制系统资源的利用率(见下文)。

    嗯,你可以将解析任务变成一个操作,当然。不过,这是否有意义取决于:

    是否要将特定任务(或功能)设为NSOperation 取决于以下考虑因素:

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

    • 另一个原因是将操作与特定的执行上下文相关联,该执行上下文本身与特定的共享和有限系统资源(如 CPU、内存、IO 等)相关联。这使您可以控制例如并行数执行需要一定系统资源的操作。假设您有一个“磁盘绑定”任务。在这种情况下,您可以创建一个并发操作数为 1 的NSOperationQueue,并为其指定一个特定的“角色”和一个合适的名称,例如“DiskBoundQueue”。队列帮助您控制操作的创建和启动,并强制限制并行执行操作的数量,以免耗尽受限的系统资源。然后,将“磁盘绑定”操作添加到专用的“DiskBoundQueue”。由于磁盘在同时从不同任务访问时运行不佳,因此将并发操作数设置为 1。也就是说,这样的专用队列有助于优化系统资源的利用率。

    • 如果您在操作之间存在依赖关系,假设您只想在操作 A 和操作 B 已成功完成的情况下启动操作 C。 NSOperation 提供了一种建立此类依赖关系的方法。

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

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


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

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

    如果您有 另一个 操作依赖于 XML 解析器的结果,那么一种方法是将 XML 解析器封装在 NSOperation 中,然后使其他操作依赖于 XML 解析器手术。 (不过,对于此类依赖项还有其他更简单的解决方案)

    【讨论】:

    • 感谢您的详细回答,非常有趣的东西:)
    【解决方案2】:
    1. 这并不立即有意义。我的猜测是使用标准机制可以提供最佳性能。但是,操作中也会执行成功/失败块。

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2011-08-09
        • 1970-01-01
        • 2021-08-10
        • 1970-01-01
        • 2019-12-05
        • 2013-09-19
        • 1970-01-01
        • 1970-01-01
        • 2017-09-05
        相关资源
        最近更新 更多