この記事では、音楽やその他のファイル、HTTPのサポートのダウンロードを説明しています。
我々は2つのクラスを作成する必要があり
HYDownLoaderを:メインクラスの音楽は、あなたが新しいダウンロード、ダウンロードの一時停止を作成することができ、ダウンロードをキャンセルします。
HYFileTool:文書管理クラス、主にHYDownLoaderサービス、あなたはファイルが存在するかどうかを確認することができ、移動ファイル。
まず、ファイル管理ツールHYFileTool
HYFileToolクラスは、直接コードに、比較的単純な方法備考.hファイルには、より明確になっている
.hファイル
#import <Foundation/Foundation.h>
@interface HYFileTool : NSObject
/**
判断文件是否存在
@param filePath 文件路径
@return 是否存在
*/
+(BOOL)fileExists:(NSString *)filePath;
/**
获取文件大小
@param filePath 文件路径
@return 文件大小
*/
+(long long)fileSize:(NSString *)filePath;
/**
移动文件到新的路径
@param fromPath 文件的原路径
@param toPath 文件的新路径
*/
+(void)moveFile:(NSString *)fromPath toPath:(NSString *)toPath;
/**
删除文件
@param filePath 文件路径
*/
+(void)removeFile:(NSString*)filePath;
@end
.Mファイル
#import "HYFileTool.h"
@implementation HYFileTool
+(BOOL)fileExists:(NSString *)filePath{
if (filePath.length == 0) {
}
return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
}
+(long long)fileSize:(NSString *)filePath{
if (![self fileExists:filePath]) {
return 0;
}
NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
return [fileInfo[NSFileSize] longLongValue];
}
+(void)moveFile:(NSString *)fromPath toPath:(NSString *)toPath{
if (![self fileExists:fromPath]) {
return;
}
[[NSFileManager defaultManager] moveItemAtPath:fromPath toPath:toPath error:nil];
}
+(void)removeFile:(NSString*)filePath{
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
}
@end
第二に、ダウンロードHYDownLoader.hメインクラスは、
最初HYDownLoader.hに列挙ダウンロードステータスを定義します
typedef NS_ENUM(NSUInteger,HYDownloadState){
HYDownloadStatePause,
HYDownloadStateDowning,
HYDownloadStateSuccess,
HYDownloadStateFail
};
そして、さまざまな状態のブロックのコールバック
typedef void(^DownLoadInfoType)(long long totalSize);
typedef void(^ProgressBlockType)(float progress);
typedef void(^SuccesswBlockType)(NSString *path);
typedef void(^FailBlockType)(void);
typedef void(^StateChangeBlockType)(HYDownloadState state);
そして、対応する属性を定義します
/**
下载状态
*/
@property(nonatomic,assign,readonly) HYDownloadState state;
/**
下载进度
*/
@property(nonatomic,assign,readonly) float progress;
/**
下载信息回调
*/
@property(nonatomic,copy) DownLoadInfoType downLoadInfo;
/**
下载状态改变回调
*/
@property(nonatomic,copy) StateChangeBlockType stateChangeInfo;
/**
下载进度改变回调
*/
@property(nonatomic,copy) ProgressBlockType progressChange;
/**
下载成功回调
*/
@property(nonatomic,copy) SuccesswBlockType successBlock;
/**
下载失败回调
*/
@property(nonatomic,copy) FailBlockType failBlock;
そして方法
/**
下载文件
@param url 下载文件的网络地址
*/
-(void)downLoader:(NSURL *)url;
/**
下载文件
@param url 下载文件的网络地址
@param downLoadInfo 下载信息block
@param progressBlock 下载进度block
@param successBlock 下载成功block
@param failedBlock 下载失败block
*/
-(void)downLoader:(NSURL *)url downLoadInfo:(DownLoadInfoType)downLoadInfo progress:(ProgressBlockType)progressBlock success:(SuccesswBlockType)successBlock failed:(FailBlockType)failedBlock;
/**
暂停当前任务
*/
-(void)pauseCurrentTask;
/**
取消当前任务
*/
-(void)cancelCurrentTask;
/**
取消并清除当前任务
*/
-(void)cancelAndClean;
三、HYDownLoader.m変数
変数は内部メソッドHYDownLoader.m必須定義しました
@interface HYDownLoader()<NSURLSessionDataDelegate>{
long long _tempSize;//已下载文件大小
long long _totalSize;//文件总大小
}
@property (nonatomic,strong) NSURLSession *session;
@property (nonatomic,weak) NSURLSessionDataTask *dataTask;
/**
下载文件完成后的路径
*/
@property (nonatomic,copy) NSString *downloadedPath;
/**
下载文件时的路径
*/
@property (nonatomic,copy) NSString *downloadingPath;
/**
写入文件的流
*/
@property (nonatomic,strong) NSOutputStream *outputStream;
@end
getおよびsetメソッドに対応
-(NSURLSession*)session{
if (_session == nil) {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
-(void)setState:(HYDownloadState)state{
if (_state == state) {
return;
}
_state = state;
if (self.stateChangeInfo) {
self.stateChangeInfo(_state);
}
if (state == HYDownloadStateSuccess && self.successBlock) {
self.successBlock(_downloadedPath);
}
if (state == HYDownloadStateFail && self.failBlock) {
self.failBlock();
}
}
-(void)setProgress:(float)progress{
_progress = progress;
if (self.progressChange) {
self.progressChange(progress);
}
}
SETSTATE、私たちはブロックを対応するダウンロードステータスコールバックに応じて、外の世界をどこに知らせます。
第四に、のダウンローダHYDownLoader.mをダウンロードするための主な方法:とdownloadWithURL:オフセット:
-(void)downLoader:(NSURL *)url{
//如果任务存在,当前只是暂停,则继续下载
if ([url isEqual:self.dataTask.originalRequest.URL] && self.state == HYDownloadStatePause) {
[self resumeCurrenttask];
return;
}
//1.文件的存放
//下载时存放到temp(此目录用于存放临时文件,app退出时会被清理)
//下载完成后移动到cache(iTunes不会备份此目录,此目录下文件不会在app退出时删除)
NSString *fileName = url.lastPathComponent;
self.downloadedPath = [kCachePath stringByAppendingPathComponent:fileName];
self.downloadingPath = [kTmpPath stringByAppendingPathComponent:fileName];
//1.判断url地址对应的资源是否已下载完成
//1.1如果已完成,则返回相关信息
if([HYFileTool fileExists:self.downloadedPath]){
NSLog(@"已下载完成(文件已存在)");
self.state = HYDownloadStateSuccess;
return;
}
[self downloadWithURL:url offset:0];
//2.否则检查临时文件是否存在
//2.1若存在,以当前已存在文件大小,作为开始字节请求资源。
if ([HYFileTool fileExists:self.downloadingPath]) {
//获取本地文件大小(已下载部分)
_tempSize = [HYFileTool fileSize:self.downloadingPath];
[self downloadWithURL:url offset:_tempSize];
return;
}
// 本地大小 == 总大小 则移动到cache文件夹
// 本地大小 > 总大小 则删除本地缓存,重新从0开始下载
// 本地大小 < 总大小 从本地大小开始下载
//2.2 不存在,则从0字节开始请求资源
[self downloadWithURL:url offset:0];
}
限り、各ブロックへの割り当てなど、時間のブロックとのコールバックメソッドを記述し、上記のダウンロードにmainメソッドを呼び出します。
-(void)downLoader:(NSURL *)url downLoadInfo:(DownLoadInfoType)downLoadInfo progress:(ProgressBlockType)progressBlock success:(SuccesswBlockType)successBlock failed:(FailBlockType)failedBlock{
self.downLoadInfo = downLoadInfo;
self.progressChange = progressBlock;
self.successBlock = successBlock;
self.failBlock = failedBlock;
[self downLoader:url];
}
ダウンローダ:メソッドが唯一の判断の現在の状態で行われ、コアが実際にdownloadWithURLでダウンロード:オフセット:メソッドを。ネットワーク要求を使用してNSURLSessionシステム。HTTP1.1プロトコル(RFC2616)は、並列ダウンロードのための技術的なサポートを提供するファイル、の部分へのアクセス、およびHTTPをサポートするために始めました。それはヘッダからの送信要求は、2つのパラメータによって実装時間に対応する、範囲は、クライアント、対応する応答がContent-範囲はサーバです。だから、キーは、HTTPリクエスト、レンジリクエストヘッダを設定する要求は、要求がオフセットデータの唯一の背面を示していることです。
/**
根据开始字节,请求资源
@param url 下载url
@param offset 开始字节
*/
- (void)downloadWithURL:(NSURL *)url offset:(long long)offset{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:0];
[request setValue:[NSString stringWithFormat:@"bytes=%lld-",offset] forHTTPHeaderField:@"Range"];
self.dataTask = [self.session dataTaskWithRequest:request];
[self resumeCurrenttask];
}
NSURLSessionは、コールバックプロキシモードを要求します。HYDownLoaderはNSURLSessionDataDelegateエージェントを追跡し、3つのエージェントがそれらをコールバック完了します:
#pragma mark - 协议
//接收到响应头
- (void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSHTTPURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler{
NSLog(@"%@",response);
_totalSize = [response.allHeaderFields[@"Content-Length"] longLongValue];
NSString *contentRangeStr = response.allHeaderFields[@"Content-Range"];
if (contentRangeStr.length > 0) {
_totalSize = [[[contentRangeStr componentsSeparatedByString:@"/"] lastObject] longLongValue];
}
self.downLoadInfo(_totalSize);
if (_tempSize == _totalSize) {
//文件移动到完成文件夹
NSLog(@"下载完成,移动文件到完成文件夹");
[HYFileTool moveFile:_downloadingPath toPath:_downloadedPath];
completionHandler(NSURLSessionResponseCancel);
self.state = HYDownloadStateSuccess;
return;
}
if (_tempSize > _totalSize) {
//删除临时缓存
[HYFileTool removeFile:self.downloadingPath];
//重新下载
[self downLoader:response.URL];
//取消请求
completionHandler(NSURLSessionResponseCancel);
}
//继续接受数据
self.state = HYDownloadStateDowning;
self.outputStream = [NSOutputStream outputStreamToFileAtPath:self.downloadingPath append:YES];
completionHandler(NSURLSessionResponseAllow);
}
//继续接收数据
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
_tempSize += data.length;
self.progress = 1.0 * _tempSize / _totalSize;
[self.outputStream write:data.bytes maxLength:data.length];
NSLog(@"接受数据");
}
//请求结束
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
NSLog(@"接收完成");
if (error == nil) {
[HYFileTool moveFile:self.downloadingPath toPath:self.downloadedPath];
self.state = HYDownloadStateSuccess;
}else{
if(error.code == -999){
NSLog(@"取消下载");
self.state = HYDownloadStatePause;
}else{
NSLog(@"下载错误%@",error);
self.state = HYDownloadStateFail;
}
}
[self.outputStream close];
}
コア・ポイント我々は、以下に詳細に説明しました:
- completionHandlerコールバックを介してヘッダ情報didReceiveResponseを受信した後、後続のコンテンツの判定動作は、このような解除要求として、またはデータを受信し続けます
- 双方向のOutputStreamストリームでファイルに書き込みます。
- 文書を受信した後コールバックdidCompleteWithErrorを停止します:方法、今回3例がある:正常終了は、ユーザがエラーに応じて個別に判断することができるなど、アボート、キャンセル。