音楽(ファイル)をダウンロードしたブレークポイント

この記事では、音楽やその他のファイル、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];
}

コア・ポイント我々は、以下に詳細に説明しました:

  1. completionHandlerコールバックを介してヘッダ情報didReceiveResponseを受信した後、後続のコンテンツの判定動作は、このような解除要求として、またはデータを受信し続けます
  2. 双方向のOutputStreamストリームでファイルに書き込みます。
  3. 文書を受信した後コールバックdidCompleteWithErrorを停止します:方法、今回3例がある:正常終了は、ユーザがエラーに応じて個別に判断することができるなど、アボート、キャンセル。

完全なコード:
https://github.com/dolacmeng/HYDownLoader

公開された103元の記事 ウォン称賛55 ビュー380 000 +

おすすめ

転載: blog.csdn.net/dolacmeng/article/details/88686286