网络:下载进度条

来源:互联网 发布:ipv6 端口格式 编辑:程序博客网 时间:2024/05/23 20:14
#import "ViewController.h"#import "ProgressButton.h"@interface ViewController ()<NSURLConnectionDataDelegate>@property (nonatomic, assign) long long fileSize; // 文件总大小@property (nonatomic, assign) long long currentLocalSize; // 本地文件的大小@property (nonatomic, assign) long long currentSize; // 当前接收的文件大小@property (nonatomic, strong) NSOutputStream *output; // 文件输出流@property (nonatomic, strong) NSURLConnection *connection; // 下载请求连接@property (nonatomic, copy) NSString *filePath; // 文件保存的路径@property (weak, nonatomic) IBOutlet ProgressButton *progressBtn;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];}/** 1. 判断本地文件是否存在 2. 获取服务器文件大小 3. 判断本地文件大小跟服务器文件大小的关系 3.1 如果本地文件大小 小于 服务器的 断点续传 文件大小 3.2 如果本地文件大小 等于 服务器的 不需要再次下载 文件大小 3.3 如果本地文件大小 大于 服务器的 先删除本地的文件,再重新下载 0 **/// 断点续传 下一次下载,从上一次下载到的地方开始- (IBAction)pause:(id)sender {    // 取消下载,只能取消,如果下一次开始下载,又重新开始    [self.connection cancel];}// 我们在使用别人的软件的时候,点击下载会怎么样?// 提示这个文件是多大,是否下载- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {    [self serverFileSize];}// HEAD用来请求查看文件大小- (void)serverFileSize {    // NSURL    NSString *URLStr =@"http://localhost/01UI基础复习.mp4";    // 百分号转码    URLStr = [URLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];    NSURL *url = [NSURL URLWithString:URLStr];    // NSURLRequest 获取文件大小,不是使用GET,而是使用HEAD    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    [request setHTTPMethod:@"HEAD"];    NSHTTPURLResponse *response;    // 获取文件大小,是使用同步    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];    // 建议保存的文件名//        NSLog(@"%@",response.suggestedFilename);     self.filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];    self.fileSize = response.expectedContentLength;    NSLog(@"%@",self.filePath);    //    NSLog(@"%lld",fileSize);    // 提示用户文件总大下,是否需要下载    // 检查本地文件大小    self.currentLocalSize = [self checkLocalFile];    if (self.currentLocalSize == self.fileSize) {        NSLog(@"下载成功");        return;    }    // 断点续传 0 , 100000    // 下载文件    [self download:url];}- (long long)checkLocalFile {    long long fileSize = 0;    // 下载之前先判断本地文件跟服务器文件之前的关系    NSFileManager *manager = [NSFileManager defaultManager];    // 文件属性    NSDictionary *att = [manager attributesOfItemAtPath:self.filePath error:NULL];    // 全到本地文件的大小    long long localFileSize = att.fileSize;    if (localFileSize > self.fileSize) { // 删除本地文件        // 删除        [manager removeItemAtPath:self.filePath error:NULL];        fileSize = 0;    }else if (localFileSize == self.fileSize) {        // 不需要重新下载        fileSize = localFileSize;    }else { // 本地文件小于服务器文件        fileSize = localFileSize;    }    return fileSize;}// 断点续传第三方框架 很少有第三方框架去实现// ASIHTTP(好几年没更新)- (void)download:(NSURL *)url {    dispatch_async(dispatch_get_global_queue(0, 0), ^{        // NSURLRequest 下载文件,从服务器获取的意思 GET        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];        NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLocalSize];        // 设置Range头        [request setValue:range forHTTPHeaderField:@"Range"];        // 开始下载文件, 知道下载的进度        // 代理回调的线程,跟执行这一行代码的线程是同一个        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];        //        NSLog(@"开始下载文件");        // 开启运行循环,才能让子线程保持        // 什么时候需要开启运行循环        /**         1. 子线程需要保持,NSTimer         2. 代理回调(代理,block)         */        [[NSRunLoop currentRunLoop] run];    });}#pragma mark - NSURLConnection 代理/** NSFileHandle 选择写入文件的方式初始化,在写入文件之前先把光标移动文件的最后,写完之后关闭 NSOutputStream 初始化的时候选择拼接文件,再打开流,写入数据(多次),关闭流 */// 接收到响应- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {    // 如果使用了Range头,响应的状态码是206    NSLog(@"接收到响应%@ -- %lld",response,response.expectedContentLength);    //    NSHTTPURLResponse *httpResp    //    self.fileSize = response.expectedContentLength; // 文件总大小    self.output = [[NSOutputStream alloc]initToFileAtPath:self.filePath append:YES];    // 在写入编辑文件之前,打开文件    [self.output open];}// 如果代理方法在主线程中执行/** 1. 方法会调用很多次 2. 如果主线程没空,不会调用代理(视力滚动的时候,或者在做其他事情),也就是相当于不下载 */- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    //    NSLog(@"接收到数据 %zd",data.length);    // 如果需要知道进度,首要要知道文件的总大小,还要接收了多少    self.currentSize += data.length;    CGFloat progress = (CGFloat)self.currentSize / self.fileSize;    NSLog(@"%f", progress);    // 设置进度视图    dispatch_async(dispatch_get_main_queue(), ^{       self.progressBtn.progress = progress;     });    // uunt8_t -> NSData    //    [NSData dataWithBytes:<#(nullable const void *)#> length:<#(NSUInteger)#>]    [self.output write:data.bytes maxLength:data.length];    NSLog(@"%@",[NSThread currentThread]);}- (void)connectionDidFinishLoading:(NSURLConnection *)connection {    NSLog(@"下载完成了");    // 关闭文件流    [self.output close];}- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {    NSLog(@"出错了");}@end
#import <UIKit/UIKit.h>@interface ProgressButton : UIButton@property (nonatomic, assign) CGFloat progress; // 进度@property (nonatomic, assign) CGFloat lineWidth; // 线宽@end#import "ProgressButton.h"@implementation ProgressButton- (void)setProgress:(CGFloat)progress {    _progress = progress;    self.lineWidth = 20;    [self setNeedsDisplay];    // 设置标题    [self setTitle:[NSString stringWithFormat:@"%0.2f%%",_progress * 100] forState:UIControlStateNormal];}- (void)drawRect:(CGRect)rect {    CGFloat width = rect.size.width;    CGFloat height = rect.size.height;    // 圆的中点    CGPoint center = CGPointMake(width * 0.5, height * 0.5);    // 半径    CGFloat radius = (MIN(width, height) - self.lineWidth) * 0.5;    // 开始角度    CGFloat startAngle = - M_PI_2;    // 结束角度    CGFloat endAngle = M_PI * 2 * self.progress + startAngle;    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];    // 设置线宽    [path setLineWidth:self.lineWidth];    // 设置颜色    [[UIColor redColor]set];    [path stroke];}@end
0 0
原创粉丝点击