网络编程归纳总结七阶段
来源:互联网 发布:国外的导航软件 编辑:程序博客网 时间:2024/05/17 21:56
网络编程归纳总结七阶段
断点续传
文件下载的时候不能像上一个练习中一样,文件存在不能直接删除文件。应该做一些决策
判断本地文件,如果本地文件存在要判断文件的大小
如果没有本地文件,下载
如果本地文件存在,发送Head请求获取服务器文件大小
本地文件大小==服务器文件大小,不下载
本地文件大小< 服务器文件大小,从之前的位置开始下载
本地文件大小> 服务器文件大小,删除本地文件,从新下载
检查服务器文件
//获取服务器上文件的信息(文件名和文件大小)- (void)checkServerInfo:(NSURL *)url{ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"head"; NSURLResponse *response = nil; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL]; //通过属性记录文件的大小,拼接要保持的文件的路径 self.expectedContentLength = response.expectedContentLength; self.targetPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];}
检查本地文件
//如果没有文件 返回0 从头下载//如果文件的大小>服务器文件大小 返回0 删除文件 从头下载//如果文件的大小=服务器文件大小 返回文件大小 如果大小下等,不用再次下载//如果文件的大小<服务器文件大小 返回文件大小- (long long)checkLocalInfo{ NSFileManager *manager = [NSFileManager defaultManager]; long long fileSize = 0; //检查是否有文件 if ([manager fileExistsAtPath:self.targetPath]) { //获取文件大小 NSDictionary *attrsDic = [manager attributesOfItemAtPath:self.targetPath error:NULL]; fileSize = attrsDic.fileSize; //获取文件大小// NSLog(@"%lld",[attrsDic[NSFileSize] longLongValue]);// NSLog(@"%lld",attrsDic.fileSize); } if (fileSize > self.expectedContentLength) { //如果本地的文件大小。比服务器的大。删除 [manager removeItemAtPath:self.targetPath error:NULL]; fileSize = 0; } return fileSize;}
下载
如果本地文件和服务器文件大小相等,不下载
//检查本地文件 long long fileSize = [self checkLocalInfo]; NSLog(@"%lld",fileSize); if (fileSize == self.expectedContentLength) { NSLog(@"已经下载"); return; }
从指定偏移处开始下载
//从指定偏移出下载文件- (void)downloadFile:(NSURL *)url offset:(long long)offset{ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:15]; self.currentFileSize = offset; //range的取值 //bytes=x-y 从x字节开始下载,下载到y字节 //bytes=x- 从x字节开始下载,直到最后 //bytes=-x 从0字节开始下载,下载到x字节//range: bytes=x-y NSString *rangeStr = [NSString stringWithFormat:@"bytes=%lld-",offset]; [request setValue:rangeStr forHTTPHeaderField:@"range"]; //设置connection的代理 NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self]; //开始 [conn start];}
异步下载
默认代理的方法都在主线程上执行,下载会卡死
异步下载NSURLConnection的代理方法,想在子线程上执行的话必须开启消息循环把下载方法中的所有代码都放在异步队列中执行- (void)download:(NSString *)urlStr[[NSOperationQueue new] addOperationWithBlock:^{}]在指定位置处开启消息循环,消息循环的模式必须是default模式NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self]; //启动消息循环 [[NSRunLoop currentRunLoop] run];
下载完成后的回调
下载完成或出错之后要在主界面做提示,现在所有的下载操作都封装在Downloader这个类中学习SDWebImage中的做法,给下载操作传入需要的block,当下载完成或出错的时候调用
修改Downloader头文件中的下载方法,增加需要的block,进度、完成、出错的block
修改Downloader.m中的实现方法,因为具体的进度、完成、出错都是在URLConnection的代理方法实现,所以传入block后需要定义属性接收
对应的位置调用回调方法
//URLConnection的下载方法中调用进度的回调,在当前子线程中执行if (self.progressBlock) { self.progressBlock(progress); }
URLConnection的下载完成的方法中调用完成的回调,下载完成会回归主线程调用,在主线程上更新界面
if (self.successBlock) { dispatch_async(dispatch_get_main_queue(), ^{ self.successBlock(self.targetPath); }); }
URLConnection的下载出错的方法中调用出错的回调,在哪个线程执行由调用者决定
if (self.errorBlock) { self.errorBlock(error); }
如果文件已经在,也要调用完成的回调
controller中调用
下载进度提示
界面上放置一个自定义按钮,设置大小
创建按钮的自定义类(按钮必须是custom的)
定义一个progress的属性,把进度传过来
每当给progress属性赋值的时候调用setNeedsDisplay重绘
- (void)setProgress:(CGFloat)progress{ _progress = progress; [self setTitle:[NSString stringWithFormat:@"%0.2f%%",progress*100] forState:UIControlStateNormal]; [self setNeedsDisplay];}
画进度
重写drawRect方法,根据progress画圆
- (void)drawRect:(CGRect)rect { UIBezierPath *path = [UIBezierPath bezierPath]; CGSize size = self.frame.size; //原点 CGPoint center = CGPointMake(size.width/2, size.height/2); //半径 CGFloat radius = (MIN(size.width, size.height) - 5)/2; //起始位置 从最上面开始画 CGFloat startAngle = -M_PI_2; //结束位置 CGFloat endAngle = 2*M_PI*self.progress+startAngle; [path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; path.lineWidth = 5; path.lineCapStyle = kCGLineCapRound; [[UIColor orangeColor] setStroke]; [path stroke];}
暂停下载
//暂停下载,暂停下载就是调用connection的cancel方法- (void)pause{ [self.conn cancel];}
下载管理类和缓存池
示例代码:
//创建下载的管理类HMDownloaderManager,单例+ (instancetype)defaultManager{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance;}
下载,调用下载器的下载方法
定义缓存池,当开始下载,把下载器缓存起来
下载之前先判断缓存池中是否有下载操作
下载完成或失败后,从缓存池移除下载操作—–最终解决重复下载的问题
下载管理类
- (void)download:(NSString *)urlStr progress:(void (^)(float))progress success:(void (^)(NSString *))success error:(void (^)(NSError *))error{ //创建下载器之前。先判断针对该文件是否有下载操作 if ([self.downloadCache objectForKey:urlStr] != nil) { NSLog(@"正在下载"); return; } //1 下载器 HMDownloader *downloader = [[HMDownloader alloc] init]; //2 把下载器添加到缓存池 [self.downloadCache setObject:downloader forKey:urlStr]; //3 下载 [downloader download:urlStr progress:progress success:^(NSString *targetPath) { [self.downloadCache removeObjectForKey:urlStr]; //下载完成 if (success != nil) { success(targetPath); } } error:^(NSError *e) { [self.downloadCache removeObjectForKey:urlStr]; //出错 if (error != nil) { error(e); } }];}
Downloader改成NSOperation
+ (instancetype)downloader:(NSString *)urlStr progress:(void (^)(float))progress success:(void (^)(NSString *))success error:(void (^)(NSError *))error{ HMDownloader *downloader = [[HMDownloader alloc] init]; downloader.progressBlock = progress; downloader.successBlock = success; downloader.errorBlock = error; downloader.urlStr = urlStr; return downloader;}- (void)main{ @autoreleasepool { NSURL *url = [NSURL URLWithString:str]; //1 检查服务器文件信息 [self checkServerInfo:url]; //2 检查本地文件 long long fileSize = [self checkLocalInfo]; // NSLog(@"%lld",fileSize); if (fileSize == self.expectedContentLength) { NSLog(@"已经下载"); if (self.successBlock) { dispatch_async(dispatch_get_main_queue(), ^{ self.successBlock(self.targetPath); }); } return; } //3 根据本地文件的长度 从对应偏移位置开始下载 [self downloadFile:url offset:fileSize]; }}
取消下载操作
- (void)pause:(NSString *)urlStr{ if ([self.downloadCache objectForKey:urlStr] == nil) { NSLog(@"没有此下载操作"); return; } JSDownloader *downloader = [self.downloadCache objectForKey:urlStr]; //暂停 connection [downloader pause]; //取消操作 [downloader cancel]; //把操作从缓存池中移除 [self.downloadCache removeObjectForKey:urlStr];}下载操作中还要取消正在执行的操作//取消正在执行的操作 if (self.isCancelled) { return; }
最近才开始往github上放东西 在公司写的又不能放= = 大家姑且看看吧
github地址: https://github.com/FuThD
- 网络编程归纳总结七阶段
- 网络编程归纳总结二阶段
- 网络编程归纳总结三阶段
- 网络编程归纳总结四阶段
- 网络编程归纳总结五阶段
- 网络编程归纳总结六阶段
- 网络编程归纳总结八阶段
- 网络编程归纳总结九阶段
- 网络编程归纳总结一阶段
- windows网络编程_阶段总结(1)
- 网络阶段总结
- OSI七层网络协议归纳
- Python网络爬虫阶段总结
- 实训阶段知识总结和归纳(一)
- 实训阶段知识总结和归纳(二)
- java学习阶段归纳总结记录-for循环嵌套
- 网络编程(七)
- 网络编程学习(七)
- 1935 error
- 另外几种Java集合框架详解
- 工作小记(六)----学习方法
- java 字符集转换
- 2015年中国互联网千里马俱乐部–年度盘点
- 网络编程归纳总结七阶段
- Vim入门
- 获取所有的th标签的内容,遍历内容
- iOS学习路线图
- Windows安装多个Tomcat服务
- 第十五章 动态规划
- [未完成]对于渲染阴影场景的unitcube剔除方法
- Android Touch事件详解
- android studio下JNI开发流程