写点什么

对比 iOS 网络组件:AFNetworking VS ASIHTTPRequest

  • 2013-02-28
  • 本文字数:4217 字

    阅读完需:约 14 分钟

在开发 iOS 应用过程中,如何高效的与服务端 API 进行数据交换,是一个常见问题。一般开发者都会选择一个第三方的网络组件作为服务,以提高开发效率和稳定性。这些组件把复杂的网络底层操作封装成友好的类和方法,并且加入异常处理等。

那么,大家最常用的组件是什么?这些组件是如何提升开发效率和稳定性的?哪一款组件适合自己,是 AFNetworking(AFN)还是 ASIHTTPRequest(ASI)?几乎每一个 iOS 互联网应用开发者都会面对这样的选择题,要从这两个最常用的组件里选出一个好的还真不是那么容易。

单单从两个控件版本提交的时间节点来看,AFN 的第一个提交是 2011 年的 1 月 1 日,那个时候 ASI 早已是 1.8+ 的版本了;而当 AFN 发布 1.0 版,2012 年 10 月份的时候,ASI 早早的已经停止更新了。这样看起来,AFN 是 ASI 的继任者,似乎不存在之前提到的选择困难的问题,而事实并非如此。本文将从用法、功能、性能和原理几个方面对二者进行简单对比,看看二者之间到底存在着怎样的区别,到底应该如何选择。

1、用法对比

首先,从推荐用法上就可以看出二者设计理念上大有不同。

图1,AFN 的示例代码,发起请求(出自: Posts.m

AFN 官方推荐的使用方法是,为一系列相关的请求定义一个 HTTPClient ,共用一个 BaseURL。每次请求把 URL 中除 BaseURL 的 Path 部分做为参数传给 HTTPClient 的静态方法,并注册一个 Block 用于回调。

图2,ASI 示例代码,发起异步请求(出自: ASIHTTPRequestTests.m

ASI 推荐使用方法就非常传统,每一个请求都由构造方法初始化一个(共享)实例,通过这个实例配置参数并发起请求。ASI 最初使用 delegate 模式回调,在 iOS SDK 支持 Block 之后也提供了注册 Block 的实例方法。

以上引用的两段代码都出自各自项目的示例工程。对比两段代码可以很清楚的看出,同样是发起一个最普通的异步请求,使用 AFN 只需要调用一个静态方法,但代码可读性较差;而 ASI 的示例看起来更清晰,但需要调用多个实例方法才能完成一次请求。AFN 的设计更加工程化,或者说对使用者更友好,而 ASI 的设计更经典,典型的 OOP。

除了初级用法上的区别,二者的高级功能和对扩展的支持也颇有不同。

2、高级功能

AFN 只封装了一些常用功能,满足基本需求,而直接忽略了很多扩展功能。例如:AFN 默认没有封装同步请求,如果开发者需要使用同步请求,则需要重写 getPath:parameters:success:failure 方法,对 AFHTTPRequestOperation 进行同步处理;而 ASI 则是直接通过调用一个 startSynchronous 方法。

此外 AFN 针对 JSON XML PList Image 四种数据结构封装了各自处理器,开发者可以把处理器注册到操作队列中,直接在回调方法中获得格式化以后的数据。在示例工程中就使用了 JSON 处理器:把 AFJSONRequestOperation 注册到操作队列里。

图3,AFN 示例代码,初始化自定义的HTTPClient(出自: AFAppDotNetAPIClient.m

而 ASI 在这方面显得更原始,没有针对任何数据类型做特别封装,只是预留了各种接口和工具供开发者自行扩展。ASI 比 AFN 提供更多扩展功能还有一个原因,它把许多内部用到的功能也抽象成类和方法。例如:

ASIHTTPRequestDataCompressor 和 ASIHTTPRequestDataDecompressor 两个类,只用于压缩本地文件,构造 POST Body 和解压缩返回数据,但这两个类仍然被设计为独立功能,提供了对多种数据结构进行压缩和解压缩的方法。

对比二者的高级功能和对扩展的支持后,可以看出 AFN 把初级功能(或者叫常用功能)做到了 90 分。调用方式够简单,处理器够丰富,使用者用起来可以算是轻松加愉快。但它放弃了对高级功能的支持,要满足较复杂的需求,就要大费周折了,在这方面最多只有 40 分。而 ASI 显然不满足于做好初级功能,但为了提供更丰富的可扩展接口,导致初级功能用起来也要花上一些力气。虽然 ASI 单独提供了支持 Amazon S3 Rackspace Cloud Files 的控件,但对于生在红旗下的我朝开发者来说基本没用,所以在初级功能的支持上 ASI 能得个 70 分,牺牲了初级功能的易用性,换来的是良好的扩展性,在高级功能的使用上远远好于 AFN,也能得个 70 分。

从使用角度对比过后,基本上对这两个项目有一个整体上的认识,再深入下去看看二者的性能如何。

3、性能对比

我分别用 AFN 和 ASI 进行了测试,测试环境如下:iPhone5,联通 3G 信号全满,室内静止状态,请求国内双线机房独立服务器的静态文件,1~20K 共 20 个文件,每个文件请求 20 次,记录从创建请求到完全下载文件的耗时,结果如下:

图4,AFN 连续访问1 ~ 20K 文件耗时

图5,ASI 连续访问1 ~ 20K 文件耗时

图4 是AFN 的记录图,绿色为20 次请求中耗时最久的一次,蓝色为耗时最短的一次,黄色为去除最大值和最小值的18 次平均值。从这个图可以看出,AFN 最开始创建对象耗时近2.5 秒,随后稳定下来,在3K、7K、15K 和20K 时出现了抖动。图5 是ASI 做相同测试的结果,首次创建对象近2.25 秒,略优于AFN,同样在5K、11K、13K、14K 和16K 发生了一些抖动,但抖动幅度似乎小于AFN,可见稳定性更好一些。

下边是把二者的测试结果放在一起的对比图,可以更直观的比较二者的区别。

图6,ASI 和AFN 耗时最大值对比

图6 的最大值对比可以更明显的看出二者的抖动对比,ASI 略好一些。

图7,ASI 和AFN 耗时最小值对比

图7 的最小值对比可以看出,在每一个大小的测试中ASI 的最佳性能似乎都要优于AFN。

图8,ASI 和AFN 耗时平均值对比

图8 是耗时平均值的对比,更能够说明问题。文件小于12K 的测试中ASI 的性能优势并没有非常明显,超过12K 以后,ASI 优势开始明显起来,每一次请求都要比AFN 节约20% ~ 30%,近0.1 秒。同时从这张图上还可以看出,随着下载文件变大,请求耗时并不是线形增长的,这是由于一次请求大部分时间都消耗在建立连接上,而真正接收数据只占用了极少时间,这个问题不在本篇文章的讨论范围,所以不多说,有兴趣的读者可以移步 http://segmentfault.com/t/ios 进一步讨论。

4、原理分析

ASI 的性能似乎全面优于 AFN,那下边从二者的实现原理上看一下到底是什么原因造成这种差距。ASI 基于 CFNetwork 框架开发,而 AFN 基于 NSURL,底层的区别是导致二者性能差距的重要原因之一。

图9,ASI 和AFN 以及底层框架的关系

我们知道所有网络通信的基础是Socket,一个Socket 与另一个连接并传送数据。BSD Socket 是一类最常见的Socket 抽象接口。

Core Foundation 框架中的 CFSocket 就是基于 BSD Socket 开发的。它几乎涵盖了 BSD Socket 的全部功能,更重要的是把 Socket 整合到事件的处理循环中。Core Founda-tion 中较高层的 CFStream 是基于 CFSocket 开发的读写流支持。

CFNetwork 是基于 Core Foundation 中 CFStream 的一个底层高性能网络框架,它由提供基础服务的 CFSocketStream,支持 HTTP 协议的 CFHTTP,基于 CFHTTP 用于身份认证的 CFHTTPAuthentication 和支持 FTP 协议的 CFFTP 组成。

正如图 9 所示,ASI 是基于 CFHTTP 开发的一个组件;而 AFN 的基础——NSURL,也是基于 CFNetwork 开发的。也就是说 ASI 相比 AFN 更加底层,这就从一定程度上造成二者的性能差距。

另一个方面,虽然二者都使用 NSOperation 和 NSOperationQueue 实现但底层的区别也导致实现方式上有非常大的差别。

ASI 的直接操作对象 ASIHTTPRequest 是 NSOperation 的子类,实现了 NSCopying 协议。在 initialize 和 initWithURL: 方法中初始化相关属性并配置一系列请求相关参数默认值。此外,ASIHTTPRequest 还提供了一系列的实例方法用来配置请求对象。在异步请求的处理上,ASIHTTPRequest 对象初始化结束后,在 startAsynchronous 方法中把对象加入共享操作队列。此后,包括创建 CFHTTPMessageRef,也就是处理网络请求的主要对象(事实上是一个指向 __CFHTTPMessage 结构的指针),在内的所有操作都在 ASIHTTPRequest 对象所属的子线程中完成。

AFN 的直接操作对象 AFHTTPClient 不同于 ASI,是一个实现了 NSCoding 和 NSCopying 协议的 NSObject 子类。AFHTTPClient 是一个封装了一系列操作方法的“工具类”,处理请求的操作类是一系列单独的,基于 NSOperation 封装的,AFURLConnectionOperation 的子类。AFN 的示例代码中通过一个静态方法,使用 dispatch_once() 的方式创建 AFHTTPClient 的共享实例,这也是官方建议的使用方法。在创建 AFHTTPClient 的初始化方法中,创建了 OperationQueue 并设置一系列参数默认值。在 getPath:parameters:success:failure 方法中创建 NSURLRequest,以 NSURLRequest 对象实例作为参数,创建一个 NSOperation,并加入在初始化发方中创建的 NSOperationQueue。以上操作都是在主线程中完成的。在 NSOperation 的 start 方法中,以此前创建的 NSURLRequest 对象为参数创建 NSURLConnection 并开启连结。

在异步回调的处理上二者也有区别,ASI 采取的是 CFHTTP 请求完成,直接回调 ASIHTTPRequest 的实例方法,通过储存的实例对象记录的信息完成 Delegate 模式或 Block 模式的回调。而 AFN 则直接使用了 NSOperation 的 completionBlock 属性。

这些实现方式也可以看出,ASI 显得更加底层,并没有过多使用 Cocoa 框架中已经封装的 API,而 AFN 则更加实用主义,逻辑简单清晰,大量使用了框架 API。这一点也是造成二者性能差别的原因之一。

总结

通过以上的对比,基本可以这样评价:AFN 适合逻辑简单的应用,或者更适合开发资源尚不丰富的团队,因为 AFN 的易用性要比 ASI 好很多,而这样的应用(或团队)对底层网络控件的定制化要求也非常低。ASI 更适合已经发展了一段时间的应用,或者开发资源相对丰富的团队,因为往往这些团队(或他们的应用)已经积累了一定的经验,无论是产品上还是技术上的。需求复杂度就是在这种时候高起来,而且底层订制的需求也越来越多,此时 AFN 就很难满足需求,需要牺牲一定的易用性,使用 ASI 作为网络底层控件。SegmentFault 开源客户端现在被设计为一款简单的阅读客户端,几乎没有定制要求,因此,目前我选择了 AFN 作为网络控件。

以上对 ASI 和 AFN 两款最常用的 iOS 底层网络控件做了初步的介绍,要更深入的了解两款控件,还需要大家继续研究各自的源码。大家遇到任何关于 iOS 的技术问题都可以在 http://segmentfault.com/t/ios 进行讨论。另外大家也可以持续关注 SegmentFault 的开源客户端,与更多的开发者共同探讨 iOS 开发技术。

作者简介

高嘉峻(微博: @gaosboy ),SegmentFault.com 联合创始人,杭州 iOS 开发者沙龙发起人,资深 iOS 开发者。

2013-02-28 00:0146593

评论

发布
暂无评论
发现更多内容

需要转变ITSM策略的12个信号,您中了几个?

龙智—DevSecOps解决方案

软件测试 | 性能测试整体规划

测吧(北京)科技有限公司

测试

国内高校最大的云上科研智算平台在复旦大学正式上线

新云力量

智能 计算 复旦大学 云上科研智算平台

Bean生命周期的扩展点:Bean Post Processor

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟 企业号 6 月 PK 榜

《2023 信创软件品牌影响力报告》发布!融云入选「信创生态」代表厂商

融云 RongCloud

IT 品牌 信创 数字 融云

AIGC+灵活用工|延长行业生命线、改写传统用工模式,还得看AI的!

TE智库

人工智能 人力资源 灵活用工 AIGC 生成式AI

AIGC+客服|智能客服上岗即失业?AI对话背后的学问大着呢

TE智库

人工智能 智能客服 AIGC 生成式AI

云原生时代,如何通过极狐GitLab x KubeSphere 构建安全应用?

极狐GitLab

DevOps 云原生 DevSecOps KubeSphere 安全左移

如何充分利用制作游戏原型的免费资产,加速游戏开发

龙智—DevSecOps解决方案

游戏开发 游戏引擎

Vue3从入门到精通

EquatorCoco

vue.js Vue vue3.0

RocketMQ on openEuler 提供高性能消息队列的稳定性解决方案

openEuler

Linux cpu 操作系统 openEuler 内核

扫码登录认证技术原理介绍及实践

互联网工科生

程序员

一个斜杠引发的CDN资源回源请求量飙升

互联网工科生

CDN

inBuilder今日分享丨开源许可协议简介

inBuilder低代码平台

基于OpenHarmony开发的玻璃拟态天气应用(3)构建天气组件并实现毛玻璃效果

路北路陈

前端 HarmonyOS OpenHarmony应用开发 6 月 优质更文活动

华为云Classroom一站式教学实践平台,开启云端教学新征程

华为云PaaS服务小智

云计算 华为云 线上教学 线上培训

开源之夏2023中选结果公示,504名高校生将投入开源项目贡献

openEuler

Linux 开源 操作系统 openEuler 实习

华秋一文带你读懂eMMC芯片引脚定义和工作原理

华秋电子

科兴未来|中国•湖州海外青创大赛全面开启!

科兴未来News

环保 #双创赛事# 新能源行业 湖州

金融科技领先者Broadridge选择CloudBees CI来加速软件交付

龙智—DevSecOps解决方案

ci 持续集成

英特尔以领先产品,为AI领域客户提供高性能和高性价比

E科讯

第十四届夏季达沃斯论坛|英特尔王锐:AI驱动工业元宇宙,释放数实融合无穷潜力

E科讯

什么是Buck电源?矽力杰SQ51201值得关注

华秋电子

软件测试 | 性能测试范围

测吧(北京)科技有限公司

测试

龙蜥白皮书精选:面向芯片研发和验证的操作系统 SiliconFastOS

OpenAnolis小助手

开源 操作系统 芯片 龙蜥社区 SiliconFastOS

OSPO才是企业拥抱开源的正确选项——适兕访谈录

开源雨林

开源 OSPO LFAPAC

Windows 系统下怎么获取 UDP 本机地址

高端章鱼哥

浮点数-Float-Double转二进制在线工具

入门小站

软件测试 | 性能工具规划

测吧(北京)科技有限公司

测试

免费沉浸式Twitter翻译工具 ZipZapAI用AI打破语言障碍

Ricky

ChatGPT GPT-4 ChatGPT4 chatgpt插件

对比iOS网络组件:AFNetworking VS ASIHTTPRequest_Android/iOS_高嘉峻_InfoQ精选文章