iOS网络请求框架ASIHTTPRequest的一些tips

之前做的项目中有一个下载文件功能。

该模块使用了ASIHttpRequst,有友好的进度显示,可暂停、删除任务,下载完成后可点击打开:

 p9      p10

下面是下载模块的类图:

p12

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

其中Downloadable类作为一个下载实体,负责自身请求的开始暂停和删除,以及数据的存储;DownloadManager维护请求队列;DownloadableTableViewCell通过实现委托DownloadableDelegate来将数据更新到UI上;DownloadableTableViewController负责接收用户操作,调度DownloadManager来完成任务。

 

ASIHTTPRequest是对CFNetwork的封装,对外接口比较友好。通过实现ASIHTTPRequestDelegate委托可以获取请求开始、接收到响应头部、结束、出错时的回调。通过实现ASIHTTPProgressDelegate委托可以获取请求每次获取到数据时候的回调。虽然看似使用简便,但是用起来还是有些地方需要注意:

Tips1:使用setDownloadDestinationPathsetTemporaryFileDownloadPath可分别设置下载的目标地址和临时地址,但是他们都不会自动创建,需要在之前创建好。

Tips2:ASIHTTProgressDelegate中值得注意的是,request:didReceiveBytes:showAccurateProgress=YES时才会每接收到一小段数据时都会调用,反之只会在请求结束时才收到一次调用;并且,在出现断线重连时候,第一次调用request:didReceiveBytes:收到的是之前下载好的数据的大小。

Tips3:ASIHTTPProgressDelegate中的request:incrementDownloadSize:可获得当前需要下载的数据量,第一次请求时在这里可获得文件的Content-Length即总大小,而之后的请求(暂停后恢复或断线重连)获得的是需要下载的数据量。ASIHTTPRequest是通过在http请求头部的Content-Range来完成断点续传的。

Tips4:如果实现了ASIHTTPProgressDelegate中的request:didReceiveData:,则setDownloadDestinationPathsetTemporaryFileDownloadPath都会无效,这时需要自己控制数据的存储。

Tips5:当下载文件不存在导致404时,并不会触发requestFailed,而是会把404页面下载到本地文件中。需要在request:didReceiveResponseHeaders:中获取到request.responseStatusCode,判断是404后做错误处理。

Tips6:之前在调试下载一个文件时进度一直有误,在分析ASIHTTPRequest源代码后发现问题所在:

在下载某些文件时,request:(ASIHttpRequest *)request didRecieveBytes:(long long)bytes只调用了一次,且bytes1

分析源代码后发现,在ASIHttpRequest.m文件中2256行可知,当在获取下载文件的content-length为空时,会自动将showAccurateProgress设为NO,代码如下:

else if ([self showAccurateProgress] && [self shouldResetDownloadProgress])

{

[theRequest setShowAccurateProgress:NO];
[theRequest incrementDownloadSizeBy:0];
}

尝试修改代码为[theRequest setShowAccurateProgress:YES],无效。再次分析代码,在ASIHttpRequest.m文件的1720行:

- (void)updateDownloadProgress
{

if (![self responseHeaders]||[self needsRedirect]||!([self contentLength]||[self complete]))

{

return;
}

}

可以看到,当contentLength0时不会去更新进度,因此可以设置一个假的不为0Content-Length如下:

else if ([self showAccurateProgress] && [self shouldResetDownloadProgress])

{

[theRequest setContentLength:1];

[theRequest setShowAccurateProgress:YES];
[theRequest incrementDownloadSizeBy:0];
}

这样在下载数据时request:didRecieveBytes:能正常调用了。

那么,为何ASIHttpRequest选择在http头部字段Content-Length为空时不更新进度呢?猜想原因应该是:在ASIHttpRequest中允许使用者通过设置[request setDownloadProgressDelegate:myProgressView]来自动更新一个UIProgressView,那么在不知道下载数据的总大小的情况下,无法计算出下载了百分之多少数据,因此更新会出问题,所以选择不更新进度。

对于http的请求返回Content-Length有如下两种情况:

情况1.服务器的responseTransfer-Encoding:chunked的形式时,表示数据是分块发送的,指示客户端这些数据不需要等到全部传输完成再进行解析,此时数据总长度Content-Length便不存在了。例如一些运算比较复杂且需要用户及时的得到最新结果,那就会采用chunked编码将内容分块输出。

情况2.除了如1所述之外的情况一般都是可以获取到Content-Length的。

ASIHTTPRequest已经不在更新了,总感觉使用起来不踏实。选择封装NSURLConnection也会是一个不错的选择。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>