AFNetworking实现 断点续传
platform:ios,'7.0'
pod "AFNetworking","~> 2.3.0"
简单思路:通过重组progressBlock , successBlock ,requestUrl ,outPutStream,然后利用AFNetworking自带的pause,resume即可妥妥的实现。
不过碰到了一些问题也挺折磨人的,文件输入流,初始化就碰到问题了,
1.[self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:YES]
如果追加了原始文件的data,就无法在下载过程中从outPutStream中获取到data。
[self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:NO]
如果不追加,续传就成覆盖了。
官方文档也没仔细看,所幸就使用不追加的方式,然后手动同步文件与输入流。 方法如下
-(void)readCacheToOutStreamWithPath:(NSString*)path;
2.pause之后,AFHTTPRequestOperation.totalBytesRead,仍然记录这之前的读取长度,如果resume了,这是content-length发生了变法,这个时候就需要从组progressBlock了,同时也需要将totalBytesRead设为0,因为是私有属性,所以就用KVC。
[self.requestOperation setValue:@"0" forKey:@"totalBytesRead"];
#define Vedio @"http://221.228.249.82/youku/697A5CA0CEB3582FB91C4E3A88/03002001004E644FA2997704E9D2A7BA1E7B9D-6CAB-79A9-E635-3B92A92B3500.mp4"
#define Picture @"http://x1.zhuti.com/down/2012/11/29-win7/3D-1.jpg"
- (IBAction)download:(id)sender
{
NSString* path = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/temp"];
NSLog(@"path = %@",path);
operation = [[DownLoadOperationalloc] init];
[operationdownloadWithUrl:Picture
cachePath:^NSString *{
return path;
} progressBlock:^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) {
NSLog(@"bytesRead = %u ,totalBytesRead = %llu totalBytesExpectedToRead = %llu",bytesRead,totalBytesRead,totalBytesExpectedToRead);
float progress = totalBytesRead / (float)totalBytesExpectedToRead;
[self.progressViewsetProgress:progressanimated:YES];
[self.labelsetText:[NSStringstringWithFormat:@"%.2f%%",progress*100]];
UIImage* image = [UIImageimageWithData:operation.requestOperation.responseData];
[self.imageViewsetImage:image];
} success:^(AFHTTPRequestOperation *operation,id responseObject) {
NSLog(@"success");
// UIImage* image = [UIImage imageWithData:operation.responseData];
// [self.imageView setImage:image];
} failure:^(AFHTTPRequestOperation *operation,NSError *error) {
NSLog(@"error = %@",error);
}];
}
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
@interface DownLoadOperation :NSObject
@property(nonatomic ,strong) NSURL* url;
@property(nonatomic ,copy) NSString* (^cachePath)(void);
@property(nonatomic ,strong) AFHTTPRequestOperation* requestOperation;
@property(nonatomic ,copy) void(^progressBlock)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead);
-(void)downloadWithUrl:(id)url
cachePath:(NSString* (^) (void))cacheBlock
progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock
success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure;
@end
#import "DownLoadOperation.h"
@implementation DownLoadOperation
-(void)downloadWithUrl:(id)url
cachePath:(NSString* (^) (void))cacheBlock
progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock
success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure
{
self.cachePath = cacheBlock;
//获取缓存的长度
longlong cacheLength = [[selfclass] cacheFileWithPath:self.cachePath()];
NSLog(@"cacheLength = %llu",cacheLength);
//获取请求
NSMutableURLRequest* request = [[selfclass] requestWithUrl:urlRange:cacheLength];
self.requestOperation = [[AFHTTPRequestOperationalloc] initWithRequest:request];
[self.requestOperationsetOutputStream:[NSOutputStreamoutputStreamToFileAtPath:self.cachePath()append:NO]];
//处理流
[selfreadCacheToOutStreamWithPath:self.cachePath()];
[self.requestOperationaddObserver:selfforKeyPath:@"isPaused"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];
//获取进度块
self.progressBlock = progressBlock;
//重组进度block
[self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];
//获取成功回调块
void (^newSuccess)(AFHTTPRequestOperation *operation,id responseObject) = ^(AFHTTPRequestOperation *operation,idresponseObject){
NSLog(@"responseHead = %@",[operation.responseallHeaderFields]);
success(operation,responseObject);
};
[self.requestOperationsetCompletionBlockWithSuccess:newSuccess
failure:failure];
[self.requestOperationstart];
}
#pragma mark - 获取本地缓存的字节
+(longlong)cacheFileWithPath:(NSString*)path
{
NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];
NSData* contentData = [fhreadDataToEndOfFile];
return contentData ? contentData.length :0;
}
#pragma mark - 重组进度块
-(void(^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))getNewProgressBlockWithCacheLength:(longlong)cachLength
{
typeof(self)newSelf =self;
void(^newProgressBlock)(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) = ^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead)
{
NSData* data = [NSDatadataWithContentsOfFile:self.cachePath()];
[self.requestOperationsetValue:dataforKey:@"responseData"];
// self.requestOperation.responseData = ;
newSelf.progressBlock(bytesRead,totalBytesRead + cachLength,totalBytesExpectedToRead + cachLength);
};
return newProgressBlock;
}
#pragma mark - 读取本地缓存入流
-(void)readCacheToOutStreamWithPath:(NSString*)path
{
NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];
NSData* currentData = [fhreadDataToEndOfFile];
if (currentData.length) {
//打开流,写入data,未打卡查看 streamCode = NSStreamStatusNotOpen
[self.requestOperation.outputStreamopen];
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
NSInteger dataLength = [currentDatalength];
constuint8_t * dataBytes = [currentDatabytes];
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.requestOperation.outputStreamwrite:&dataBytes[bytesWrittenSoFar]maxLength:dataLength - bytesWrittenSoFar];
assert(bytesWritten !=0);
if (bytesWritten == -1) {
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != dataLength);
}
}
#pragma mark - 获取请求
+(NSMutableURLRequest*)requestWithUrl:(id)url Range:(longlong)length
{
NSURL* requestUrl = [urlisKindOfClass:[NSURLclass]] ? url : [NSURLURLWithString:url];
NSMutableURLRequest* request = [NSMutableURLRequestrequestWithURL:requestUrl
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5*60];
if (length) {
[request setValue:[NSStringstringWithFormat:@"bytes=%lld-",length]forHTTPHeaderField:@"Range"];
}
NSLog(@"request.head = %@",request.allHTTPHeaderFields);
return request;
}
#pragma mark - 监听暂停
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context
{
NSLog(@"keypath = %@ changeDic = %@",keyPath,change);
//暂停状态
if ([keyPathisEqualToString:@"isPaused"] && [[changeobjectForKey:@"new"]intValue] ==1) {
longlong cacheLength = [[selfclass] cacheFileWithPath:self.cachePath()];
//暂停读取data从文件中获取到NSNumber
cacheLength = [[self.requestOperation.outputStreampropertyForKey:NSStreamFileCurrentOffsetKey]unsignedLongLongValue];
NSLog(@"cacheLength = %lld",cacheLength);
[self.requestOperationsetValue:@"0"forKey:@"totalBytesRead"];
//重组进度block
[self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];
}
}
@end
AFNetworking实现 断点续传的更多相关文章
- AFNetworking实现程序重新启动时的断点续传
今天需要用AFNetworking实现断点续传的功能,但是在进行了一番研究之后,发现AFNetworking虽然支持下载文件的暂停和继续,但是程序重新启动后再次下载无法进行续传.网上有说可以通过AFD ...
- AFNetworking 3.0 断点续传 使用记录
最近项目中用到了压缩包下载,使用AFNetworking 3.0 下载压缩包 支持断点续传 代码如下: #import "HDInternet_handler.h" #import ...
- AFNetworking 下载文件断点续传操作
一:本示例代码包括: 文件下载,写入指定目录 下载进度,回调Progress; 断点续传,下载暂停,继续操作: 二:本项目 适用于 AFNetworking 1.x 版本 #pragma mark 断 ...
- 使用 AFNetworking做过断点续传吗?
断点续传的主要思路: 检查服务器文件信息 检查本地文件 如果比服务器文件小, 断点续传, 利用 HTTP 请求头的 content-range实现断点续传(如果content-range不存在就取Co ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- AFNetworking到底做了什么?(二)
接着上一篇的内容往下讲,如果没看过上一篇内容可以点这: AFNetworking到底做了什么? 之前我们讲到NSUrlSession代理这一块: 代理8: /* task完成之后的回调,成功和失败 ...
- AFNetworking、MKNetworkKit和ASIHTTPRequest对比
之前一直在使用ASIHTTPRequest作为网络库,但是由于其停止更新,iOS7上可能出现更多的问题,于是决定更换网络库. 目前比较流行的网络库主要有AFNetworking和MKNetworkKi ...
随机推荐
- HDU 4116 Fruit Ninja
http://acm.hdu.edu.cn/showproblem.php?pid=4116 题意:给N个圆,求一条直线最多能经过几个圆?(相切也算) 思路:枚举中心圆,将其他圆的切线按照极角排序,并 ...
- Qt编程之在QGraphics scene中使用图片
http://stackoverflow.com/questions/5960074/qimage-in-a-qgraphics-scene http://stackoverflow.com/ques ...
- T-SQL函数类别统计
- Android Spinner使用简介
Android中使用Spinner作为下拉列表,下面直接看实现方式: (1)使用ArrayAdapter来实现: 实现步骤: 1. 在布局文件中定义Spinner组件: 2. 向Spinner添加需要 ...
- win10 iis 创建新站点注意事项
新建站点时:注意文件夹权限增加everyone. 快速打开IIS:win+r:inetmgr
- JVM基础和调优(二)
主要讲述java虚拟机的内存体系结构 了解了JVM 的一些基础之后,我们来看看java虚拟机内存的体系结构,这个是理解JVM垃圾收集算法的前提,理解了内存结构我们才能够针对不同的部分根据我们的程序进行 ...
- 【案例】舒邑:一个女装品牌的奇葩打法-@i黑马
[案例]舒邑:一个女装品牌的奇葩打法-@i黑马 [案例]舒邑:一个女装品牌的奇葩打法
- Android Studio:Unable to add window android.view.ViewRootImpl$W@5e2d85a -- permission denied for this window 第一行代码
学习<第一行代码>的时候,出现的错误. java.lang.RuntimeException: Unable to start receiver com.example.sevenun.l ...
- BUG出现的地方真的令我这个测试新人想象不到
今天上班,仍然在等待下一阶段项目的研发完成. 没有正式测试任务的我,作为新手肯定要趁着这个时间好好学习了,偶尔再拿出公司已经上线发布的APP来到处看看. 就在这偶尔的情况下让我发现了一个在正式测试时根 ...
- Java清洁:终结处理和垃圾回收
一般情况:Java有垃圾回收机制负责回收无用对象占据的内存资源. 特殊情况:假定你的对象(并非使用new)获得一块特殊的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道如何释放 ...