发出许多网络请求的 iOS 应用程序的最佳架构?

Posted

技术标签:

【中文标题】发出许多网络请求的 iOS 应用程序的最佳架构?【英文标题】:Best architecture for an iOS application that makes many network requests? 【发布时间】:2011-06-16 04:01:22 【问题描述】:

我正在重新考虑我正在开发的大型应用的请求架构的方法。我目前正在使用 ASIHTTPRequest 来实际发出请求,但由于在不同的视图控制器中采取了许多不同的操作,我需要许多不同类型的请求,因此我正在尝试找出组织这些请求的最佳系统。

我目前正在构建由应用程序委托保留的单例“请求者”,并坐在那里监听表示需要发出请求的 NSNotification;他们发出请求,监听响应,并发送一个带有响应数据的新 NSNotification。这解决了我的大部分问题,但不能优雅地处理失败的请求或对同一个单例请求者的并发请求。

是否有人成功设计了一个清晰的 OO 架构以在 ios 应用程序中发出许多不同类型的请求?

【问题讨论】:

好问题:我也一直在研究这个问题的答案,因为有人为 NSURLConnection 创建了一个连接管理器,该管理器适用于一个连接,但不适用于多个连接。 【参考方案1】:

在尝试了几种方法之后,这是一种给我带来出色结果的架构,易于记录、理解、维护和扩展:

我有一个负责网络连接的对象,我们称之为“网络管理器”。通常,此对象是一个单例(使用 Matt Gallagher's Cocoa singleton macro 创建)。 由于您使用 ASIHTTPRequest(我总是这样做,很棒的 AP​​I),所以我在我的网络管理器中添加了一个 ASINetworkQueue ivar。我让网络管理员成为该队列的代表。 我为我的应用程序所需的每种网络请求(通常为每个后端 REST 交互或 SOAP 端点)创建 ASIHTTPRequest 的子类。这还有另一个好处(详情见下文:) 每次我的控制器需要一些数据(刷新、viewDidAppear 等)时,网络管理器都会创建所需 ASIHTTPRequest 子类的实例,然后将其添加到队列中。 ASINetworkQueue 负责处理带宽问题(取决于您使用的是 3G、EDGE 还是 GPRS 或 Wifi,您拥有更多带宽,并且可以处理更多请求等)。这是由队列完成的,这很酷(至少,这是我理解这个队列所做的事情之一,我希望我没有弄错:)。 每当请求完成或失败时,都会调用网络管理器(请记住,网络管理器是队列的代表)。 网络管理员不知道如何处理每个请求的结果;因此,它只是在请求上调用一个方法!请记住,请求是 ASIHTTPRequest 的子类,因此您可以只放置管理请求结果的代码(通常,将 JSON 或 XML 反序列化为真实对象,触发其他网络连接,更新 Core Data 存储等)。将代码放入每个单独的请求子类中,使用跨请求类的通用名称的多态方法,可以很容易地调试和管理恕我直言。 最后,我使用通知通知上面的控制器有趣的事件;使用委托协议不是一个好主意,因为在您的应用中,您通常有许多控制器与您的网络管理员通信,然后通知更加灵活(您可以让多个控制器响应相同的通知等)。

无论如何,这就是我一段时间以来一直这样做的方式,坦率地说,它运作良好。我可以横向扩展系统,根据需要添加更多的 ASIHTTPRequest 子类,并且网络管理器的核心保持不变。

希望对你有帮助!

【讨论】:

好答案!你如何测试你的系统?我的另一个大问题是提出一种易于单元测试的架构。 一个快速想到的事情,如果你只有一个班级对你的回复感兴趣,你可以使用块而不是通知。 作为更新,我现在大量使用该架构(我们有 20-30 种不同类型的请求),而且它的扩展性非常好。 我刚刚发布了一篇博文,展示了此架构的示例实现:akosma.com/2011/09/20/… 鉴于最近宣布不再支持 ASIHTTPRequest,我将在不久的将来调整 Senbei 以支持 AFNetworking。【参考方案2】:

这是我通常的做法。我也有一个用于发出网络请求的单例对象。对于必须经常发出的请求,我有一个接受 AFHTTPRequestOperations(或 AFJSONRequestOperations)的 NSOperationQueue,因为我通常使用 AFNetworking 发出请求。对于这些,存在在请求成功或失败时执行的 completionBlock 和 failureBlock 属性。在我的单例对象上,我将有一个用于启动特定网络请求的方法,并且作为该方法的参数,我将包含一个成功和失败块,可以将其传递到该方法中定义的块中。这样,整个应用程序都可以发出网络请求,此时应用程序的范围对传递给方法的块中的单例可用。例如...(使用 ARC)

        @implementation NetworkManager

    -(void)makeRequestWithSuccess:(void(^)(void))successBlock failure:(void(^)(NSError *error))failureBlock

    
        NSURL *url = [NSURL URLWithString:@"some URL"];

        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
            [responseObject doSomething];

            if (successBlock)
                dispatch_async(dispatch_get_main_queue(), successBlock);

         failure:^(AFHTTPRequestOperation *operation, NSError *error) 

            if (failureBlock)
                dispatch_async(dispatch_get_main_queue(), ^
                    failureBlock(error);
                );
        ];

        [self.operationQueue addOperation:op];
    
@end

而且您始终可以让成功块采用您需要传递的任何参数。

【讨论】:

【参考方案3】:

fully-loaded 项目值得一读。

【讨论】:

我以前见过满载的——它很好地处理了一个特定的问题,但我正在寻找一种解决方案来处理具有不同响应的不同类型的请求。满载处理请求的方式与我在问题中详述的类似,nsnotifications 和 asihttprequest 完成了繁重的工作。我正在寻找更可扩展和更强大的东西,即使它只是一种组织通知和请求的创造性方式。 我想到的另一个代码示例是 Apple 的 MVCNetworking 示例中的 Networking 文件夹,不过我没有任何经验可以发表任何评论。 有趣。我得看看这个。【参考方案4】:

试试STNetTaskQueue,它可以使您的请求可重用和可维护。

【讨论】:

以上是关于发出许多网络请求的 iOS 应用程序的最佳架构?的主要内容,如果未能解决你的问题,请参考以下文章

REST网络请求

并行处理许多 API 请求与异步/等待 [关闭]

Python + requests + splinter:发出多个并发“get”请求的最快/最佳方法是啥?

从网站抓取数据的3种最佳方法

如何重新发出网络请求?我必须重新创建 Webclient 吗?

Ionic 3 应用程序停止发出网络请求