您的位置:首页 > 移动开发 > Objective-C

Objective-C利用AFN实现图片下载,支持断点续传,显示下载进度

2016-01-05 11:07 627 查看
AFN导入就不多说了,建议用cocoapods,并且建议装个插件管理器,很方便。AFN介绍也不多说了,以后写个详细的,今天主要写断点续传那点事。

直接进入主题

新建一个类,继承自NSObject,我命名为DownLoadOperation

头文件重定义属性和方法如下

@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 long totalBytesExpectedToRead);

-(void)downloadWithUrl:(id)url

cachePath:(NSString* (^) (void))cacheBlock

progressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))progressBlock

success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success

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

接下来在.m中实现

-(void)downloadWithUrl:(id)url

cachePath:(NSString* (^) (void))cacheBlock

progressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))progressBlock

success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success

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

{

self.cachePath = cacheBlock;

//获取缓存的长度

long long cacheLength = [[self class] cacheFileWithPath:self.cachePath()];

//获取请求

NSMutableURLRequest* request = [[self class] requestWithUrl:url Range:cacheLength];

self.requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

[self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:NO]];

//处理流

[self readCacheToOutStreamWithPath:self.cachePath()];

[self.requestOperation addObserver:self forKeyPath:@"isPaused" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

//获取进度块

self.progressBlock = progressBlock;

//重组进度block

[self.requestOperation setDownloadProgressBlock:[self getNewProgressBlockWithCacheLength:cacheLength]];

//获取成功回调块

void (^newSuccess)(AFHTTPRequestOperation *operation, id responseObject) = ^(AFHTTPRequestOperation *operation, id responseObject){

success(operation,responseObject);

};

[self.requestOperation setCompletionBlockWithSuccess:newSuccess

failure:failure];

[self.requestOperation start];

}

#pragma mark - 获取本地缓存的字节

+(long long)cacheFileWithPath:(NSString*)path

{

NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:path];

NSData* contentData = [fh readDataToEndOfFile];

return contentData ? contentData.length : 0;

}

#pragma mark - 重组进度块

-(void(^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))getNewProgressBlockWithCacheLength:(long long)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 = [NSData dataWithContentsOfFile:self.cachePath()];

[self.requestOperation setValue:data forKey:@"responseData"];

// self.requestOperation.responseData = ;

newSelf.progressBlock(bytesRead,totalBytesRead + cachLength,totalBytesExpectedToRead + cachLength);

};

return newProgressBlock;

}

#pragma mark - 读取本地缓存入流

-(void)readCacheToOutStreamWithPath:(NSString*)path

{

NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:path];

NSData* currentData = [fh readDataToEndOfFile];

if (currentData.length) {

//打开流,写入data , 未打卡查看 streamCode = NSStreamStatusNotOpen

[self.requestOperation.outputStream open];

NSInteger bytesWritten;

NSInteger bytesWrittenSoFar;

NSInteger dataLength = [currentData length];

const uint8_t * dataBytes = [currentData bytes];

bytesWrittenSoFar = 0;

do {

bytesWritten = [self.requestOperation.outputStream write:&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:(long long)length

{

NSURL* requestUrl = [url isKindOfClass:[NSURL class]] ? url : [NSURL URLWithString:url];

NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestUrl

cachePolicy:NSURLRequestReloadIgnoringCacheData

timeoutInterval:5*60];

if (length) {

[request setValue:[NSString stringWithFormat:@"bytes=%lld-",length] forHTTPHeaderField:@"Range"];

}

return request;

}

#pragma mark - 监听暂停

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{

//暂停状态

if ([keyPath isEqualToString:@"isPaused"] && [[change objectForKey:@"new"] intValue] == 1) {

long long cacheLength = [[self class] cacheFileWithPath:self.cachePath()];

//暂停读取data 从文件中获取到NSNumber

cacheLength = [[self.requestOperation.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue];

[self.requestOperation setValue:@"0" forKey:@"totalBytesRead"];

//重组进度block

[self.requestOperation setDownloadProgressBlock:[self getNewProgressBlockWithCacheLength:cacheLength]];

}

}

这就完成90%了,接下来就是调用了

定义一个DownLoadOperation属性operation(需要导入AFHTTPRequestOperationManager.h)

布局也不多说了哈,一个下载button,一个暂停button,一个显示进度的label,外加一个UIImageView

开始下载直接调用类里面的唯一的方法就行,代码如下:

- (IBAction)download:(id)sender

{

NSString* path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/temp"];

NSLog(@"path = %@",path);

operation = [[DownLoadOperation alloc] init];

[operation downloadWithUrl:Picture

cachePath:^NSString *{

return path;//存储路径

} progressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {//这个block写下载进度

float progress = (float)totalBytesRead / (float)totalBytesExpectedToRead;

[self.progressView setProgress:progress animated:YES];

[self.label setText:[NSString stringWithFormat:@"%.0f%%",progress * 100]];

UIImage* image = [UIImage imageWithData:operation.requestOperation.responseData];

[self.imageView setImage: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);

}];

}

//暂停

- (IBAction)pasuse:(id)sender

{

[operation.requestOperation pause];

}

//重新开始

- (IBAction)resume:(id)sender

{

[operation.requestOperation resume];

}

这就完成啦~

再扯点别的哈,本想写个oc从入门到精通的系列博客,发现真的没精力,所以就偷偷懒,写一些开发中常见和常用的东西吧~欢迎交流哈~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: