AFNetworking下载学习

学习1:基本学习

- (void)downLoadImage{
//    // 方案一:基于扩展库进行网络请求
//    [image setImageWithURL:[NSURL URLWithString:@"https://www.weixiaolive.com/zb_users/upload/2023/02/202302221677076277413609.jpg"]];
//

    /*
     1)创建manager、配置manager、使用manager中的方法(GET、PUT、POST、DELETE等)
     2)manager中的方法 调用 dataTaskWithHTTPMethod:方法构建task,然后执行task([dataTask resume];)
     3)

     */
    // 方案二:普通网络请求
    // 1)创建AFHTTPSessionManager对象(创建的时候会被默认配置:session、Reachability、Security、Serialization等)
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    // 2)设置请求参数的序列化方式(有默认值,但是图片类型需要特殊说明AFImageResponseSerializer)
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFImageResponseSerializer serializer];

    // 3)get方法请求数据
    NSString *url = @"https://www.weixiaolive.com/zb_users/upload/2023/02/202302221677076277413609.jpg";

    
    [manager GET:url parameters:nil headers:nil progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"获取过程中的处理");
        
        //  注意主线程更新UI内容
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressView.progress =  1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount;
        });

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"获取成功的处理");
        self.imageView.image = responseObject;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"获取失败的处理");
    }];
}

补充问题1:更新UI的API必须在主线程中调用:
如果不在主线程中调用根据UI的API,可能会报错

image.png

学习2:断点下载

/**
 * downloadTask的懒加载
 */
- (NSURLSessionDataTask *)downloadTask {
    if (!_downloadTask) {
        // 1. 创建下载URL
        NSURL *url = [NSURL URLWithString:@"https://www.cockos.com/licecap/licecap132.dmg"];
        
        // 2. 创建request请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        
        // 设置HTTP请求头中的Range(只请求指定部分的实体)
        NSString *range = [NSString stringWithFormat:@"bytes=%zd-", self.currentLength];
        [request setValue:range forHTTPHeaderField:@"Range"];
        
        __weak typeof(self) weakSelf = self;
        
        // 3.1 调用manager中的dataTaskWithRequest方法构建downloadTask
        _downloadTask = [self.manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            NSLog(@"dataTaskWithRequest");
            
            // 设置完成回调(不然完成一次之后,下次就下载不了了)
            // 清空长度
            weakSelf.currentLength = 0;
            weakSelf.fileLength = 0;
            
            // 关闭fileHandle
            [weakSelf.fileHandle closeFile];
            weakSelf.fileHandle = nil;
            
        }];
        
        // 3.2 设置响应block(文件长度、文件路径、文件句柄、返回值)
        [self.manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
            NSLog(@"NSURLSessionResponseDisposition");
            
            // 获得下载文件的总长度:请求下载的文件长度 + 当前已经下载的文件长度
            weakSelf.fileLength = response.expectedContentLength + self.currentLength;
            
            // 沙盒文件路径
            NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"licecap132.dmg"];
            
            NSLog(@"File downloaded to: %@",path);
            
            NSFileManager *manager = [NSFileManager defaultManager];
            
            if (![manager fileExistsAtPath:path]) {
                // 如果没有下载文件的话,就创建一个文件。如果有下载文件的话,则不用重新创建(不然会覆盖掉之前的文件)
                [manager createFileAtPath:path contents:nil attributes:nil];
            }
            
            // 创建文件句柄
            weakSelf.fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
            
            /*
             NSURLSessionResponseCancel:取消请求并关闭连接。
             NSURLSessionResponseAllow:继续处理请求。
             NSURLSessionResponseBecomeDownload:将请求转化为下载任务。
             */
            // 允许处理服务器的响应,才会继续接收服务器返回的数据
            return NSURLSessionResponseAllow;
        }];
        
        // 3.3 设置数据block(根据文件句柄来判断从哪里开始写)
        [self.manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
            NSLog(@"setDataTaskDidReceiveDataBlock");
            
            // 指定数据的写入位置 -- 文件内容的最后面
            [weakSelf.fileHandle seekToEndOfFile];
            
            // 向沙盒写入数据
            [weakSelf.fileHandle writeData:data];
            
            // 拼接文件总长度
            weakSelf.currentLength += data.length;
            
            // 获取主线程,不然无法正确显示进度。
            NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
            [mainQueue addOperationWithBlock:^{
                // 下载进度
                if (weakSelf.fileLength == 0) {
                    weakSelf.progressView.progress = 0.0;
                    weakSelf.progressLabel.text = [NSString stringWithFormat:@"当前下载进度:00.00%%"];
                } else {
                    weakSelf.progressView.progress =  1.0 * weakSelf.currentLength / weakSelf.fileLength;
                    weakSelf.progressLabel.text = [NSString stringWithFormat:@"当前下载进度:%.2f%%",100.0 * weakSelf.currentLength / weakSelf.fileLength];
                }
               
            }];
        }];
    }
    return _downloadTask;
}

完整代码:DownloadLearn

bug记录:

  1. 100.04%:下载完成之后再点击下载,会导致下载进度变成100.04%,并且损坏下载的文件
    目前想到的解决办法就是:根据progressView.progress来判断是否继续下载
    (后续对这个bug有了更深刻的认知之后再补充解决办法吧。。)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容