美文网首页iOS个人修养IOSiOS开发工具
用NSURLConnection封装一个断点续传后台下载的轻量级

用NSURLConnection封装一个断点续传后台下载的轻量级

作者: CGPointZero | 来源:发表于2016-06-07 16:22 被阅读366次

    摘要

    • 本文讲述,用NSURLConnection封装一个断点下载,支持后台下载的完整的下载工具。

    效果图

    效果图

    用法示例

    [[FGGDownloadManager shredManager] downloadWithUrlString:model.url toPath:model.destinationPath process:^(float progress, NSString *sizeString, NSString *speedString) {
                    //更新进度条的进度值
                    weakCell.progressView.progress=progress;
                    //更新进度值文字
                    weakCell.progressLabel.text=[NSString stringWithFormat:@"%.2f%%",progress*100];
                    //更新文件已下载的大小
                    weakCell.sizeLabel.text=sizeString;
                    //显示网速
                    weakCell.speedLabel.text=speedString;
                    if(speedString)
                        weakCell.speedLabel.hidden=NO;
    
                } completion:^{
                    [sender setTitle:@"完成" forState:UIControlStateNormal];
                    sender.enabled=NO;
                    weakCell.speedLabel.hidden=YES;
                    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"提示" message:[NSString stringWithFormat:@"%@下载完成✅",model.name] delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
                    [alert show];
    
                } failure:^(NSError *error) {
                    [[FGGDownloadManager shredManager] cancelDownloadTask:model.url];
                    [sender setTitle:@"恢复" forState:UIControlStateNormal];
                    weakCell.speedLabel.hidden=YES;
                    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
                    [alert show];
    }];
    

    思路

    • 搞一个下载类,负责一个下载任务;
    • 搞一个下载管理类,负责下载队列;
    • 在程序进入后台时,开启后台下载;
    • 在程序被终结时取消所有下载并保存下载进度;
    • 当程序启动时,加载上次下载进度;

    下载类 FGGDownloader.h

    FGGDownloader遵循NSURLConnection的一些协议:
    @interface FGGDownloader : NSObject<NSURLConnectionDataDelegate,NSURLConnectionDelegate>
    接下来定义三个代码块:

    typedef void (^ProcessHandle)(float progress,NSString *sizeString,NSString *speedString);
    typedef void (^CompletionHandle)();
    typedef void (^FailureHandle)(NSError *error);
    

    然后声明三个只读属性:

    //下载过程中回调的代码块,会多次调用
    @property(nonatomic,copy,readonly)ProcessHandle process;
    //下载完成回调的代码块
    @property(nonatomic,copy,readonly)CompletionHandle completion;
    //下载失败的回调代码块
    @property(nonatomic,copy,readonly)FailureHandle failure;
    

    写一个快速实例的类方法:

    +(instancetype)downloader;
    

    搞一个下载的接口:

    /**
     *  断点下载
     *
     *  @param urlString        下载的链接
     *  @param destinationPath  下载的文件的保存路径
     *  @param  process         下载过程中回调的代码块,会多次调用
     *  @param  completion      下载完成回调的代码块
     *  @param  failure         下载失败的回调代码块
     */
    -(void)downloadWithUrlString:(NSString *)urlString
                          toPath:(NSString *)destinationPath
                         process:(ProcessHandle)process
                      completion:(CompletionHandle)completion
                         failure:(FailureHandle)failure;
    

    搞一个取消下载的方法:

    /**
     *  取消下载
     */
    -(void)cancel;
    

    程序启动的时候要加载上一次的下载进度:

    /**
     * 获取上一次的下载进度
     */
    +(float)lastProgress:(NSString *)url;
    

    需要在界面上显示文件下载了的大小,文件总大小:

    /**获取文件已下载的大小和总大小,格式为:已经下载的大小/文件总大小,如:12.00M/100.00M。
     *
     * @param url 下载链接
     */
    +(NSString *)filesSize:(NSString *)url;
    

    搞三个通知,因为下载管理类要用:

    /**
     *  下载完成的通知名
     */
    static NSString *const FGGDownloadTaskDidFinishDownloadingNotification=@"FGGDownloadTaskDidFinishDownloadingNotification";
    /**
     *  系统存储空间不足的通知名
     */
    static NSString *const FGGInsufficientSystemSpaceNotification=@"FGGInsufficientSystemSpaceNotification";
    /**
     *  下载进度改变的通知
     */
    static NSString *const FGGProgressDidChangeNotificaiton=@"FGGProgressDidChangeNotificaiton";
    

    下载类的实现 FGGDownloader.m

    大文件下载,要遵循低内存占用,因此我们要有一个文件读写句柄:NSFileHandle,以及一些储放下载位置、下载路径、链接等一些东西的成员变量。
    <pre>
    说明一下,_timer是为了获取网速近似值,没0.5秒计算文件增长的大小,取网速平均值.
    这里有个假设:假设文件读写不占用时间,而在这0.5秒内文件的增量直接反应网速。
    </pre>

    @implementation FGGDownloader{
        
        NSString        *_url_string;
        NSString        *_destination_path;
        NSFileHandle    *_writeHandle;
        NSURLConnection *_con;
        NSUInteger       _lastSize;
        NSUInteger       _growth;
        NSTimer         *_timer;
    }
    

    快速实例化的类方法:

    +(instancetype)downloader{
        
        return [[[self class] alloc]init];
    }
    

    初始化方法:

    -(instancetype)init{
    
        if(self=[super init]){
            
            //每0.5秒计算一次文件大小增加部分的尺寸
            _timer=[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(getGrowthSize) userInfo:nil repeats:YES];
        }
        return self;
    }
    

    计算文件没0.5秒的增量,以计算网速近似值

    //计算一次文件大小增加部分的尺寸,以计算网速近似值
    -(void)getGrowthSize
    {
        NSUInteger size=[[[[NSFileManager defaultManager] attributesOfItemAtPath:_destination_path error:nil] objectForKey:NSFileSize] integerValue];
        _growth=size-_lastSize;
        _lastSize=size;
    }
    

    关键方法,下载接口方法

    /**
     *  断点下载
     *
     *  @param urlString        下载的链接
     *  @param destinationPath  下载的文件的保存路径
     *  @param  process         下载过程中回调的代码块,会多次调用
     *  @param  completion      下载完成回调的代码块
     *  @param  failure         下载失败的回调代码块
     */
    -(void)downloadWithUrlString:(NSString *)urlString toPath:(NSString *)destinationPath process:(ProcessHandle)process completion:(CompletionHandle)completion failure:(FailureHandle)failure{
        
        if(urlString&&destinationPath){
            
            _url_string=urlString;
            _destination_path=destinationPath;
            _process=process;
            _completion=completion;
            _failure=failure;
            
            NSURL *url=[NSURL URLWithString:urlString];
            NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
            NSFileManager *fileManager=[NSFileManager defaultManager];
            BOOL fileExist=[fileManager fileExistsAtPath:destinationPath];
            if(fileExist){
                
                NSUInteger length=[[[fileManager attributesOfItemAtPath:destinationPath error:nil] objectForKey:NSFileSize] integerValue];
                NSString *rangeString=[NSString stringWithFormat:@"bytes=%ld-",length];
                [request setValue:rangeString forHTTPHeaderField:@"Range"];
            }
            _con=[NSURLConnection connectionWithRequest:request delegate:self];
        }
    }
    

    取消下载:

    /**
     *  取消下载
     */
    -(void)cancel{
        
        [self.con cancel];
        self.con=nil;
        if(_timer){
            
            [_timer invalidate];
            _timer=nil;
        }
    }
    

    程序每次启动都要获取上次的下载进度:

    /**
     * 获取上一次的下载进度
     */
    +(float)lastProgress:(NSString *)url{
        
        if(url)
            return [[NSUserDefaults standardUserDefaults]floatForKey:[NSString stringWithFormat:@"%@progress",url]];
        return 0.0;
    }
    

    通过下载链接url获取文件的大小信息(当前大小/总大小 组成的字符串)

    /**获取文件已下载的大小和总大小,格式为:已经下载的大小/文件总大小,如:12.00M/100.00M
     */
    +(NSString *)filesSize:(NSString *)url{
        
        NSString *totalLebgthKey=[NSString stringWithFormat:@"%@totalLength",url];
        NSUserDefaults *usd=[NSUserDefaults standardUserDefaults];
        NSUInteger totalLength=[usd integerForKey:totalLebgthKey];
        if(totalLength==0){
            
            return @"0.00K/0.00K";
        }
        NSString *progressKey=[NSString stringWithFormat:@"%@progress",url];
        float progress=[[NSUserDefaults standardUserDefaults] floatForKey:progressKey];
        NSUInteger currentLength=progress*totalLength;
        
        NSString *currentSize=[self convertSize:currentLength];
        NSString *totalSize=[self convertSize:totalLength];
        return [NSString stringWithFormat:@"%@/%@",currentSize,totalSize];
    }
    

    下面是个工具方法,把文件的长度(字节)转成字符串

    /**
     * 计算缓存的占用存储大小
     *
     * @prama length  文件大小
     */
    +(NSString *)convertSize:(NSUInteger)length
    {
        if(length<1024)
            return [NSString stringWithFormat:@"%ldB",(NSUInteger)length];
        else if(length>=1024&&length<1024*1024)
            return [NSString stringWithFormat:@"%.0fK",(float)length/1024];
        else if(length >=1024*1024&&length<1024*1024*1024)
            return [NSString stringWithFormat:@"%.1fM",(float)length/(1024*1024)];
        else
            return [NSString stringWithFormat:@"%.1fG",(float)length/(1024*1024*1024)];
    }
    

    下载过程可能会存储空间不足,若不做处理,会导致crash,因此每次句柄写文件时,都要判断存储空间是否足够:

    /**
     *  获取系统可用存储空间
     *
     *  @return 系统空用存储空间,单位:字节
     */
    -(NSUInteger)systemFreeSpace{
        
        NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSDictionary *dict=[[NSFileManager defaultManager] attributesOfFileSystemForPath:docPath error:nil];
        return [[dict objectForKey:NSFileSystemFreeSize] integerValue];
    }
    

    下面是NSURLConnect的代理和数据源

    下载失败,回调error block:

    #pragma mark - NSURLConnection
    /**
     * 下载失败
     */
    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        
        if(_failure)
            _failure(error);
    }
    

    在接受到响应请求的代理方法中存储文件中大小,以及初始化文件读写句柄_writeHandle:

    /**
     * 接收到响应请求
     */
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        
        NSString *key=[NSString stringWithFormat:@"%@totalLength",_url_string];
        NSUserDefaults *usd=[NSUserDefaults standardUserDefaults];
        NSUInteger totalLength=[usd integerForKey:key];
        if(totalLength==0){
            
            [usd setInteger:response.expectedContentLength forKey:key];
            [usd synchronize];
        }
        NSFileManager *fileManager=[NSFileManager defaultManager];
        BOOL fileExist=[fileManager fileExistsAtPath:_destination_path];
        if(!fileExist)
            [fileManager createFileAtPath:_destination_path contents:nil attributes:nil];
        _writeHandle=[NSFileHandle fileHandleForWritingAtPath:_destination_path];
    }
    

    下载过程的接收数据的回调,处理计算网速、下载进度、文件大小信息,存档当前大小等操作,最后回调<b><i>网速</b></i>,文件大小/总大小字符串</b></i>,<b><i>下载进度</b></i>信息:

    /**
     * 下载过程,会多次调用
     */
    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        
        [_writeHandle seekToEndOfFile];
        
        NSUInteger freeSpace=[self systemFreeSpace];
        if(freeSpace<1024*1024*20){
            
            UIAlertController *alertController=[UIAlertController alertControllerWithTitle:@"提示" message:@"系统可用存储空间不足20M" preferredStyle:UIAlertControllerStyleAlert];
            UIAlertAction *confirm=[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
            [alertController addAction:confirm];
            [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
            //发送系统存储空间不足的通知,用户可自行注册该通知,收到通知时,暂停下载,并更新界面
            [[NSNotificationCenter defaultCenter] postNotificationName:FGGInsufficientSystemSpaceNotification object:nil userInfo:@{@"urlString":_url_string}];
            return;
        }
        [_writeHandle writeData:data];
        NSUInteger length=[[[[NSFileManager defaultManager] attributesOfItemAtPath:_destination_path error:nil] objectForKey:NSFileSize] integerValue];
        NSString *key=[NSString stringWithFormat:@"%@totalLength",_url_string];
        NSUInteger totalLength=[[NSUserDefaults standardUserDefaults] integerForKey:key];
        
        //计算下载进度
        float progress=(float)length/totalLength;
        
        [[NSUserDefaults standardUserDefaults]setFloat:progress forKey:[NSString stringWithFormat:@"%@progress",_url_string]];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //获取文件大小,格式为:格式为:已经下载的大小/文件总大小,如:12.00M/100.00M
        NSString *sizeString=[FGGDownloader filesSize:_url_string];
        
        //发送进度改变的通知(一般情况下不需要用到,只有在触发下载与显示下载进度在不同界面的时候才会用到)
        NSDictionary *userInfo=@{@"url":_url_string,@"progress":@(progress),@"sizeString":sizeString};
        [[NSNotificationCenter defaultCenter] postNotificationName:FGGProgressDidChangeNotificaiton object:nil userInfo:userInfo];
        
        //计算网速
        NSString *speedString=@"0.00Kb/s";
        NSString *growString=[FGGDownloader convertSize:_growth*(1.0/0.1)];
        speedString=[NSString stringWithFormat:@"%@/s",growString];
        
        //回调下载过程中的代码块
        if(_process)
            _process(progress,sizeString,speedString);
    }
    

    下载完成,发送通知,回调下载完成的代码块:

    /**
     * 下载完成
     */
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
        
        [[NSNotificationCenter defaultCenter] postNotificationName:FGGDownloadTaskDidFinishDownloadingNotification object:nil userInfo:@{@"urlString":_url_string}];
        if(_completion)
            _completion();
    }
    

    下载管理类 FGGDownloadManager.h

    首先要导入下载类:#import "FGGDownloader.h"
    单例接口

    +(instancetype)shredManager;
    

    同样有添加下载任务的接口:

    /**
     *  断点下载
     *
     *  @param urlString        下载的链接
     *  @param destinationPath  下载的文件的保存路径
     *  @param  process         下载过程中回调的代码块,会多次调用
     *  @param  completion      下载完成回调的代码块
     *  @param  failure         下载失败的回调代码块
     */
    -(void)downloadWithUrlString:(NSString *)urlString
                          toPath:(NSString *)destinationPath
                         process:(ProcessHandle)process
                      completion:(CompletionHandle)completion
                         failure:(FailureHandle)failure;
    

    管理类自然可以暂停指定的某个下载,根据某个下载链接url,暂停某个下载

    /**
     *  暂停下载
     *
     *  @param url 下载的链接
     */
    -(void)cancelDownloadTask:(NSString *)url;
    

    管理类可以暂停所有下载任务:

    /**
     *  暂停所有下载
     */
    -(void)cancelAllTasks;
    

    管理类可以彻底移除某个下载任务:

    /**
     *  彻底移除下载任务
     *
     *  @param url  下载链接
     *  @param path 文件路径
     */
    -(void)removeForUrl:(NSString *)url file:(NSString *)path;
    

    当然管理类可以根据下载链接url获取上一次的下载进度:

    /**
     *  获取上一次的下载进度
     *
     *  @param url 下载链接
     *
     *  @return 下载进度
     */
    -(float)lastProgress:(NSString *)url;
    

    以及获取文件大小信息:

    /**
     *  获取文件已下载的大小和总大小,格式为:已经下载的大小/文件总大小,如:12.00M/100.00M。
     *
     *  @param url 下载链接
     *
     *  @return 有文件大小及总大小组成的字符串
     */
    -(NSString *)filesSize:(NSString *)url;
    

    管理类的实现 FGGDownloadManager.m

    • 在这里,我们搞了一个队列,设置了同时最多允许多少个下载任务。
    • 超过最大下载任务后,添加下载任务将会被添加进入下载任务队列,处于等待模式。
    • 当当前正在进行的下载任务数小于允许最大同时下载任务数时,队列中的一个下载任务出列(遵循先入列的先出列)。

    根据逻辑,我定制了以下成员变量

    @implementation FGGDownloadManager{
        
        NSMutableDictionary         *_taskDict;
        /**
         *  排队对列
         */
        NSMutableArray              *_queue;
        /**
         *  后台进程id
         */
        UIBackgroundTaskIdentifier  _backgroudTaskId;
    }
    

    单例方法:

    +(instancetype)shredManager
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            mgr=[[FGGDownloadManager alloc]init];
        });
        return mgr;
    }
    

    初始化的时候,注册app进入后台,app会到前台,被终结等,以及系统内存不足的通知:

    -(instancetype)init{
        
        if(self=[super init]){
            
            _taskDict=[NSMutableDictionary dictionary];
            _queue=[NSMutableArray array];
            _backgroudTaskId=UIBackgroundTaskInvalid;
            //注册系统内存不足的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemSpaceInsufficient:) name:FGGInsufficientSystemSpaceNotification object:nil];
            //注册程序下载完成的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadTaskDidFinishDownloading:) name:FGGDownloadTaskDidFinishDownloadingNotification object:nil];
            //注册程序即将失去焦点的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadTaskWillResign:) name:UIApplicationWillResignActiveNotification object:nil];
            //注册程序获得焦点的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadTaskDidBecomActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
            //注册程序即将被终结的通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadTaskWillBeTerminate:) name:UIApplicationWillTerminateNotification object:nil];
            
        }
        return self;
    }
    

    收到系统内存不足的通知时,取消下载:

    /**
     *  收到系统存储空间不足的通知调用的方法
     *
     *  @param sender 系统存储空间不足的通知
     */
    -(void)systemSpaceInsufficient:(NSNotification *)sender{
        
        NSString *urlString=[sender.userInfo objectForKey:@"urlString"];
        [[FGGDownloadManager shredManager] cancelDownloadTask:urlString];
    }
    

    程序即将失去焦点,开启后台:

    /**
     *  收到程序即将失去焦点的通知,开启后台运行
     *
     *  @param sender 通知
     */
    -(void)downloadTaskWillResign:(NSNotification *)sender{
        
        if(_taskDict.count>0){
            
            _backgroudTaskId=[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                
            }];
        }
    }
    

    程序重新获得焦点时,关闭后台:

    /**
     *  收到程序重新得到焦点的通知,关闭后台
     *
     *  @param sender 通知
     */
    -(void)downloadTaskDidBecomActive:(NSNotification *)sender{
        
        if(_backgroudTaskId!=UIBackgroundTaskInvalid){
            
            [[UIApplication sharedApplication] endBackgroundTask:_backgroudTaskId];
            _backgroudTaskId=UIBackgroundTaskInvalid;
        }
    }
    

    程序即将被终结时,取消所有下载任务:

    /**
     *  程序将要结束时,取消下载
     *
     *  @param sender 通知
     */
    -(void)downloadTaskWillBeTerminate:(NSNotification *)sender{
        
        [[FGGDownloadManager shredManager] cancelAllTasks];
    }
    

    收到下载完成的通知时,从排队队列中取出一个任务出列:

    /**
     *  下载完成通知调用的方法
     *
     *  @param sender 通知
     */
    -(void)downloadTaskDidFinishDownloading:(NSNotification *)sender{
        
        //下载完成后,从任务列表中移除下载任务,若总任务数小于最大同时下载任务数,
        //则从排队对列中取出一个任务,进入下载
        NSString *urlString=[sender.userInfo objectForKey:@"urlString"];
        [_taskDict removeObjectForKey:urlString];
        if(_taskDict.count<kFGGDwonloadMaxTaskCount){
            
            if(_queue.count>0){
                
                NSDictionary *first=[_queue objectAtIndex:0];
                
                [self downloadWithUrlString:first[@"urlString"]
                                     toPath:first[@"destinationPath"]
                                    process:first[@"process"]
                                 completion:first[@"completion"]
                                    failure:first[@"failure"]];
                //从排队对列中移除一个下载任务
                [_queue removeObjectAtIndex:0];
            }
        }
    }
    

    添加下载任务:判断是否超过允许的最大的并发任务数,若大于,则进入队列派对,反之则搞一个下载类去下载这个任务:

    -(void)downloadWithUrlString:(NSString *)urlString toPath:(NSString *)destinationPath process:(ProcessHandle)process completion:(CompletionHandle)completion failure:(FailureHandle)failure{
        
        //若同时下载的任务数超过最大同时下载任务数,
        //则把下载任务存入对列,在下载完成后,自动进入下载。
        if(_taskDict.count>=kFGGDwonloadMaxTaskCount){
            
            NSDictionary *dict=@{@"urlString":urlString,
                                 @"destinationPath":destinationPath,
                                 @"process":process,
                                 @"completion":completion,
                                 @"failure":failure};
            [_queue addObject:dict];
            
            return;
        }
        FGGDownloader *downloader=[FGGDownloader downloader];
        @synchronized (self) {
            [_taskDict setObject:downloader forKey:urlString];
        }
        [downloader downloadWithUrlString:urlString
                                   toPath:destinationPath
                                  process:process
                               completion:completion
                                  failure:failure];
    }
    

    取消下载任务:

    /**
     *  取消下载任务
     *
     *  @param url 下载的链接
     */
    -(void)cancelDownloadTask:(NSString *)url{
        
        FGGDownloader *downloader=[_taskDict objectForKey:url];
        [downloader cancel];
        @synchronized (self) {
            [_taskDict removeObjectForKey:url];
        }
        if(_queue.count>0){
            
            NSDictionary *first=[_queue objectAtIndex:0];
            
            [self downloadWithUrlString:first[@"urlString"]
                                 toPath:first[@"destinationPath"]
                                process:first[@"process"]
                             completion:first[@"completion"]
                                failure:first[@"failure"]];
            //从排队对列中移除一个下载任务
            [_queue removeObjectAtIndex:0];
        }
    }
    

    取消所有下载任务:

    -(void)cancelAllTasks{
    
        [_taskDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            FGGDownloader *downloader=obj;
            [downloader cancel];
            [_taskDict removeObjectForKey:key];
        }];
    }
    

    彻底移除下载任务:

    /**
     *  彻底移除下载任务
     *
     *  @param url  下载链接
     *  @param path 文件路径
     */
    -(void)removeForUrl:(NSString *)url file:(NSString *)path{
        
        FGGDownloader *downloader=[_taskDict objectForKey:url];
        if(downloader){
            [downloader cancel];
        }
        @synchronized (self) {
            [_taskDict removeObjectForKey:url];
        }
        NSUserDefaults *usd=[NSUserDefaults standardUserDefaults];
        NSString *totalLebgthKey=[NSString stringWithFormat:@"%@totalLength",url];
        NSString *progressKey=[NSString stringWithFormat:@"%@progress",url];
        [usd removeObjectForKey:totalLebgthKey];
        [usd removeObjectForKey:progressKey];
        [usd synchronize];
        
        NSFileManager *fileManager=[NSFileManager defaultManager];
        BOOL fileExist=[fileManager fileExistsAtPath:path];
        if(fileExist){
            
            [fileManager removeItemAtPath:path error:nil];
        }
    }
    

    根据url获取上次下载进度:

    -(float)lastProgress:(NSString *)url{
    
        return [FGGDownloader lastProgress:url];
    }
    

    根据url获取上次下载大小:

    -(NSString *)filesSize:(NSString *)url{
    
        return [FGGDownloader filesSize:url];
    }
    

    最后在销毁的时候,移除通知:

    -(void)dealloc{
    
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    

    最后附上我的GitHub代码地址:FGGDownloader,欢迎pull request和star ~

    相关文章

      网友评论

      • MrJ的杂货铺:后台10分钟左右就会停止下载了,需要在Appdelegate里配置什么吗?
        CGPointZero:@MrJ的杂货铺 background fech,貌似只能10分钟,但是10钟,足以下载很大的文件了
      • 字节码:厉害了,你的GitHub我好像去年就看到了,但是博客我才刚刚看到!
        CGPointZero:@Ossey 哈哈,多谢支持!这些都是小东小西!
      • f7139db11dcd:大家,你好厉害!

      本文标题:用NSURLConnection封装一个断点续传后台下载的轻量级

      本文链接:https://www.haomeiwen.com/subject/zcbddttx.html