虽然ASIHTTPRequest已经不再更新,大多数人选择了AFNetworking,但是还是有个别公司将ASIHTTPRequest在进行封装一下或者修改一下来满足自己公司的需求,现贴上两者区别
对比 | ASI | AFN |
更新状态 | 2012年10月份,已经停止更新 | 持续更新中,目前已更新至3.0版 |
介绍 |
ASI的直接操作对象
ASIHTTPRequest,是一个实现了了NSCopying协议的NSOperation子类。
在initialize和initWithURL:方法中初始化相关属性并配置一系列请求相关参数默认值。此外,ASIHTTPRequest还提供了一系列的实例方法用来配置请求对象。
| AFN的直接操作对象AFHTTPClient,是一个实现了NSCoding和NSCopying协议的NSObject子类。AFHTTPClient是一个封装了一系列操作方法的“工具类”,处理请求的操作类是一系列单独的,基于NSOperation封装的,AFURLConnectionOperation |
线程处理模式 |
每一个请求都由构造方法初始化一个(共享)实例,通过这个实例配置参数并发起请求。ASI最初使用delegate模式回调,在iOS SDK支持Block之后也提供了注册Block的实例方法。
ASI采取的是CFHTTP请求完成,直接回调ASIHTTPRequest的实例方法,通过储存的实例对象记录的信息完成Delegate模式或Block模式的回调。
在异步请求的处理上,ASIHTTPRequest对象初始化结束后,在startAsynchronous方法中把对象加入共享操作队列。此后,
包括创建CFHTTPMessageRef,也就是处理网络请求的主要对象(事实上是一个指向__CFHTTPMessage结构的指针),在内的所有操作都在ASIHTTPRequest对象所属的子线程中完成。
|
AFN的示例代码中通过一个静态方法,使用dispatch_once()的方式创建AFHTTPClient的共享实例,这也是官方建议的使用方法。在创建AFHTTPClient的初始化方法中,创建了OperationQueue并设置一系列参数默认值。在getPath:parameters:success:failure方法中创建NSURLRequest,以NSURLRequest对象实例作为参数,创建一个NSOperation,并加入在初始化发方中创建的NSOperationQueue。
以上操作都是在主线程中完成的。在NSOperation的start方法中,以此前创建的NSURLRequest对象为参数创建NSURLConnection并开启连结。
|
数据处理模式 | ASI在这方面显得更原始,没有针对任何数据类型做特别封装,只是预留了各种接口和工具供开发者自行扩展。 | AFN针对JSON、XML、PList和Image四种数据结构封装了各自处理器,开发者可以把处理器注册到操作队列中,直接在回调方法中获得格式化以后的数据。 |
同步请求 |
ASI则是直接通过调用一个startSynchronous方法。
| AFN默认没有封装同步请求,如果开发者需要使用同步请求,则需要重写getPath:parameters:success:failure方法,对AFHTTPRequestOperation进行同步处理 |
异步回调的处理 | 【使用AFNetworking进行网络异步请求时,block:(void(^)代码块实际返回到UI主线程中。即使在子线程中使用AFNetWorking进行网络的异步请求,block:(void(^)代码块仍然返回到UI主线程中(AF框架,它里面已经create了异步线程 |
为一系列相关的请求定义一个HTTPClient,共用一个BaseURL。每次请求把URL中除BaseURL的Path部分做为参数传给HTTPClient的静态方法,并注册一个Block用于回调。
AFN则直接使用了NSOperation的completionBlock属性。
|
基于的底层开发框架
|
CFNetwork框架
使用CFnetwork而不是Cocoa框架NSURL有几点好处。CFNetwork更加专注于网络协议,而NSURL更加专注于数据访问,比如通过HTTP或者FTP传输数据。尽管NSURL的确也提供了一些可配置功能,可是CFNetwork提供的要多的多。另外NSURL还需要你使用Objective_c。如果做不到这点的话,还是应该使用CFNetwork
|
NSURL
【使用iOS5.0 SDK NSURLConnection:
2、进行网络异步请求(sendAsynchronousRequest)时,block:(void(^)代码块实际返回到子线程中。因此,此时如需要向UI线程发送通知,则需要跳转到主线程中发送通知dispatch_async(dispatch_get_main_queue(), ^{});】
|
底层开发矿建介绍 |
CFNetwork是基于Core Foundation中CFStream的一个底层高性能网络框架,它由提供基础服务的CFSocketStream,支持HTTP协议的CFHTTP,基于CFHTTP用于身份认证的CFHTTPAuthentication和支持FTP协议的CFFTP组成。
Core Foundation框架中的CFSocket就是基于BSD Socket开发的。它几乎涵盖了BSD Socket的全部功能,更重要的是把Socket整合到事件的处理循环中。Core Founda-tion中较高层的CFStream是基于CFSocket开发的读写流支持。
| 如图所示,ASI是基于CFHTTP开发的一个组件;而AFN的基础——NSURL,也是基于CFNetwork开发的,也就是说ASI相比AFN更加底层。 |
性能对比 | AFN请求优于ASI | |
总结 | ASI更适合已经发展了一段时间的应用,或者开发资源相对丰富的团队,因为往往这些团队(或他们的应用)已经积累了一定的经验,无论是产品上还是技术上的。需求复杂度就是在这种时候高起来,而且底层订制的需求也越来越多,此时AFN就很难满足需求,需要牺牲一定的易用性,使用ASI作为网络底层控件。 | AFN适合逻辑简单的应用,或者更适合开发资源尚不丰富的团队,因为AFN的易用性要比ASI好很多,而这样的应用(或团队)对底层网络控件的定制化要求也非常低。 |
另附:iOS开发:AFNetworking、MKNetworkKit和ASIHTTPRequest比较【下图为查找的资料,尚未验证】
使用:
#import "ViewController.h"
#import "JSON.h"
#import "ASIFormDataRequest.h"
#import "Reachability.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)createDictionaryIfNotExists
{
NSString *downloadPath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/download"];
if (![[NSFileManager defaultManager]fileExistsAtPath:downloadPath])
{
[[NSFileManager defaultManager]createDirectoryAtPath:downloadPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *tempPath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/temp"];
if (![[NSFileManager defaultManager]fileExistsAtPath:tempPath])
{
[[NSFileManager defaultManager]createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:nil];
}
}
//使用ASI发起GET请求
- (IBAction)getRequestClick:(UIButton *)sender
{
NSString *urlString = @"http://api.map.baidu.com/telematics/v3/weather?location=郑州&output=json&ak=QZZGSqG9rjS1bQAAfixD9bt7&mcode=abc123";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//创建一个ASI的请求类,ASIHTTPRequest用于GET请求
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:urlString]];
//设置ASI请求的代理,请求结束后,ASI就会调用相应的代理方法。
request.delegate = self;
//设置请求结束的回调方法(须先实现协议),如果不设定,那么ASI默认调用协议中得到的结束方法;如果设定,那么就不再调用协议方法,只调用设置的方法
request.didFinishSelector = @selector(getRequsetFinish:);
//设置请求的tag值
//request.tag = 1;
//同一个界面的多种请求,在请求完成时(1)可以通过tag值区分哪个请求完成;(2)也可以发送请求时绑定不同的请求结束调用方法。
//startAsynchronous 异步请求(请求数据过程中不会阻塞主线程) ; startSynchronous 同步请求(请求过程会阻止主线程,如果网速慢或者请求的数据量比较大,就会导致主线程长时间处于卡死状态)
[request startAsynchronous];
//显示状态栏上的网络请求标志,YES表示圈一直在转
//[[UIApplication sharedApplication]setNetworkActivityIndicatorVisible:YES];
}
//发送POST请求
- (IBAction)postRequest:(UIButton *)sender
{
//ASIFormDataRequest 发送POST请求
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
//setPostValue: forKey: 添加POST参数
[request setPostValue:@"ming" forKey:@"name"];
[request setPostValue:@"20" forKey:@"age"];
request.delegate = self;
request.didFinishSelector = @selector(postRequestFinish:);
[request startAsynchronous];
}
//下载文件
- (IBAction)downloadFileClick:(UIButton *)sender
{
//如果正在下载,不再发送下载请求
if (_downloadRequest)
{
return;
}
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/FileUploadServer/net.zip"];
_downloadRequest = [ASIHTTPRequest requestWithURL:url];
//设置下载路径,设置过下载路经之后,ASI就会把这次请求当作下载请求,自动把收到的数据存入路径文件,request.responseData中就不会在自动拼数据。设置的路径文件夹必须保证存在(不会自动创建)。
[self createDictionaryIfNotExists];
NSString *path = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/download/a.zip"];
_downloadRequest.downloadDestinationPath = path;
_downloadRequest.delegate = self;
//设置下载进度代理,每当下载到新数据时,ASI就会调用代理对象的协议方法
_downloadRequest.downloadProgressDelegate = self;
_downloadRequest.didFinishSelector = @selector(downloadRequestFinish:);
//实现断点下载
//设置文件的临时下载路径 (必须保证存在) temporary,临时的
_downloadRequest.temporaryFileDownloadPath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/temp/a.zip"];
//设置是否可以断点续传 Resume ,继续
_downloadRequest.allowResumeForFileDownloads = YES;
[_downloadRequest startAsynchronous];
}
//暂停下载
- (IBAction)stopDownload:(UIButton *)sender
{
[_downloadRequest cancel];
_downloadRequest = nil;
}
//上传文件
- (IBAction)uploadFileClick:(UIButton *)sender
{
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/FileUploadServer/UploadServlet"]];
//如果上传小文件,setPostBody 直接把文件放入请求体即可
//[request setPostBody:data];
//把一个文件的数据设置到请求体中(上传大文件,直接存入硬盘)
NSString *path = [[NSBundle mainBundle]pathForResource:@"file" ofType:@"zip"];
[request setPostBodyFilePath:path];
//setShouldStreamPostDataFromDisk 设置是否使用输入流从磁盘中读取数据到请求体,对于大文件必须使用输入流读入。
[request setShouldStreamPostDataFromDisk:YES];
//设置上传进度代理
request.uploadProgressDelegate = self;
request.delegate = self;
request.didFinishSelector = @selector(uploadRequestFinish:);
[request startAsynchronous];
}
//判断当前网络状态
- (IBAction)isNetWorkClick:(UIButton *)sender
{
//Reachability 能够判断当前的网络状态
Reachability *reach = [Reachability reachabilityForInternetConnection];
switch (reach.currentReachabilityStatus)
{
case kNotReachable:
_netWorkLabel.text = @"没有网络";
break;
case kReachableViaWWAN:
_netWorkLabel.text = @"手机网络";
break;
case kReachableViaWiFi:
_netWorkLabel.text = @"WIFI网络";
default:
break;
}
//网络状态发生变化时的通知
//extern NSString *const kReachabilityChangedNotification
}
//ASI请求失败时调用
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(@"ASI请求失败原因:%@",request.error);
}
//ASI请求成功时调用
- (void)requestFinished:(ASIHTTPRequest *)request
{
//request.responseData 请求得到的数据
//request.responseString 请求数据按照UTF8转换的字符串
//NSLog(@"%@",request.responseString);
//使用 SBJSON 解析数据
NSDictionary *dic = request.responseString.JSONValue;
NSLog(@"%@",dic);
}
//请求数据时调用,如果实现了这个方法,ASI就不再自动拼接数据
//- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
//{
// NSLog(@"收到数据了");
//}
- (void)getRequsetFinish:(ASIHTTPRequest *)request
{
NSLog(@"自己设定的协议方法\n%@",request.responseString);
}
- (void)postRequestFinish:(ASIFormDataRequest *)request
{
NSLog(@"%@",request.responseString);
}
- (void)downloadRequestFinish:(ASIHTTPRequest *)request
{
NSLog(@"下载完成");
_downloadRequest = nil;
}
//每当进度更新时调用
- (void)setProgress:(float)newProgress
{
_progressVIew.progress = newProgress;
}
- (void)uploadRequestFinish:(ASIFormDataRequest *)request
{
NSLog(@"上传完成");
}