网络:下载进度条

网络:下载进度条#import”ViewController.h”#import”ProgressButton.h”@interfaceViewController()@property(nonatomic,assign)longlongfileSize;//文件总大小@property(nonatomic,assign)

大家好,又见面了,我是你们的朋友全栈君。

#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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/159269.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 电脑桌面图标点击打不开怎么办_双击桌面图标打开的是属性

    电脑桌面图标点击打不开怎么办_双击桌面图标打开的是属性在网上我们经常会看到有人提问“怎样解决笔记本电脑双击桌面图标打不开”的问题,引发该问题的原因是exe文件的关联损坏了,当然系统中毒也可能导致此现象,那么我们该如何解决这个问题呢?下面就由学习啦小编跟大家分享具体的处理方法吧,希望对大家有所帮助~笔记本电脑双击桌面图标打不开的两个处理方法笔记本电脑双击桌面图标打不开的处理方法一:1、点击屏幕左下角的开始菜单按钮,然后再点击“所有程序”;2、接着点击“…

  • 数据库开发016ExecuteReader方法「建议收藏」

    数据库开发016ExecuteReader方法「建议收藏」SqlCommand类https://docs.microsoft.com/zh-cn/dotnet/api/system.data.sqlclient.sqlcommand?view=dotnet-plat-ext-3.1构造函数 SqlCommand() 初始化SqlCommand类的新实例。 SqlCommand(String) …

  • jenkins+SVN配置「建议收藏」

    jenkins+SVN配置「建议收藏」开发项目,版本控制必不可少,我用的版本控制软件为SVN,那么如何把jenkins和SVN结合,使得SVN源码一有上传更新,jenkins就马上构建项目呢?下面说一下配置过程1)首先要在jenkins中添加svn的用户名和密码:打开“Credentials”界面进行添加,如下图2)配置项目工作空间3)配置项目:源码管理选择SVN,如下图:4)配置项目:设置构建触发器…

  • 讲座:计算机专业及其学习

    讲座:计算机专业及其学习

  • Android应用程序注冊广播接收器(registerReceiver)的过程分析

    Android应用程序注冊广播接收器(registerReceiver)的过程分析

    2021年12月14日
  • 数据库复习笔记(全覆盖,包括往年部分真题)

    ##1、数据库系统概述**1.1数据库的基本概念**数据库:长期储存在计算机内、有组织的、可共享的大量数据的集合。*基本特征:*数据按一定的数据模型组织、描述和储存可为各种用户共享、冗余度较小、易扩展数据独立性较高数据:描述事物的符号记录数据有结构的:记录是计算机存储数据的一种格式或一种方法数据库管理系统及其功能:位于…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号