iOS开发网络编程之断点续传

2020-01-15 17:02:30刘景俊

简单点说,content-length表示被下载文件的字节数。

对比原理讲解的第三步,我们可以看到如果要计算出文件的总字节数,那么必须把已经下载的字节数 加上 content-length

我们需要把每个被下载文件的总字节数存储起来,这里我们选择使用plist文件来记载,plist文件包含一个字典。设置文件名为键值,已经下载的文件字节数为值。

文件名为了防止重复,这里我们设置文件名为下载url的hash值,可以保证不重重。

实现代码如下:


- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
  self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + DownloadLength;

  NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile: TotalLengthPlist];

  if (dict == nil) dict = [NSMutableDictionary dictionary];
  dict[ Filename] = @(self.totalLength);

  [dict writeToFile: TotalLengthPlist atomically:YES];
}

上述NSSessionDelegate方法会在请求收到回应的时候调用一次,我们可以在该方法中获取回应信息,取出content-length字段。

3.封装一个方法,实现下载进度,成功,失败提示

我们可以模仿AFNetwork,把下载封装到一个方法,然后使用不同的block来实现下载进度,成功,失败后的回调。

定义如下:


-(void)downLoadWithURL:(NSString *)URL
       progress:(progressBlock)progressBlock
        success:(successBlock)successBlock
         faile:(faileBlock)faileBlock
{
  self.successBlock = successBlock;
  self.failedBlock = faileBlock;
  self.progressBlock = progressBlock;
  self.downLoadUrl = URL;
  [self.task resume];
}

上面的三个block都采用宏定义方式,这样看起来比较简洁,具体代码参考下面的完整代码。

然后我们可以在NSURLSessionDataDelegate的对应的代理方法中去实现三个block的调用,然后传入相应的参数。这样当其他人调用我们的方法,就可以在相应的block中实现回调。具体代码参考下面的完整代码

完整代码实现

下面是完整的代码实现


#import <Foundation/Foundation.h>
typedef void (^successBlock) (NSString *fileStorePath);
typedef void (^faileBlock) (NSError *error);
typedef void (^progressBlock) (float progress);

@interface DownLoadManager : NSObject <NSURLSessionDataDelegate>
@property (copy) successBlock successBlock;
@property (copy) faileBlock   failedBlock;
@property (copy) progressBlock  progressBlock;


-(void)downLoadWithURL:(NSString *)URL
       progress:(progressBlock)progressBlock
        success:(successBlock)successBlock
         faile:(faileBlock)faileBlock;

+ (instancetype)sharedInstance;
-(void)stopTask;

@end