标签:
/*--------------------------- NSOperation综合案例: 1.项目简介/UI 搭建 ----------------------------*/
重点:
1. UI 界面;
2.构建数据模型;
3.缓存开发中需要用到的数据模型.
4.在懒加载方法中,不要出现点语法.
{
1. 搭建 UI 界面
//导航控制器 + 表格视图控制器(根控制器)
//注意提供一个字典转模型的方法.
// KVC(Key - Value - Code)键值编码使用注意
// 注意与 KVO (Key - Value - Observe)键值监听的区别;
存放:
3. 将数据模型缓存到可变数组中,开发的数据直接来源于这个可变数组
//懒加载存放数据模型的数组.操作步骤:
“apps ———> 数据模型"
//懒加载存放数据模型的数组.操作步骤:
(1) 将apps.plist 文件转换为数组 (数组中存放的是数据字典): array ——> 字典模型
字典转模型
<1> 获得 apps.plist 文件 的路径(知道了文件路径,就能够找到文件)
{
//获取 apps.plist 文件名的路径
NSString *path = [[NSBundle mainBundle]pathForResource:@“apps.plist” ofType:nil];
}
<2> 根据 apps.plist 文件 转换为数组
{
//根据 apps.plist 文件 转换为数组:array 中存储的是数组字典
NSArray *array = [NSArray arrayWithContentsOfFile:path];
}
}
(2) 取出数据字典,将数据字典转换为模型,并且将模型存放在apps数组中
{
//取出数据字典,将数据字典转换为模型
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx,BOOL *stop{
//array :存放字典模型
//obj :数组中存放的字典
//idx : obj在数组中的位置
//<1> 取出数组中的数据字典
NSDictionary *dict = obj;
//<2> 将数据字典转换为数据模型
ITApp *app = [ITAppWithDictionary:dict];
// 将数据模型添加到临时可变数组中
[appArray addObject:app];
}];
//将数据模型存放在 apps 中
_apps = appsArray;
}
//注意,取出数组中的字典有两种方式:<1> for; <2> Block.推荐使用第二种.效率更好.
#pragma 懒加载
//存放数据模型的数组
-(NSMutableArray *)apps
{
if(!_apps){
_apps = [NSMutableArray array];
//获取 apps.plist 文件名的全路径
NSString * path = [[NSBundle mainBundle]pathForResource: @“apps.plist” ofFile:nil];
//根据apps.plist文件 转换为数组:array 中存储的是数据字典
NSArray * array = [NSArray arrayWithContentsOfFile:path];
//打印一下数组字典
// NSLog(@“%@“,array);
//定义一个临时的可变数组来存放数据模型:
NSMutableArray *appArray = [NSMutableArray array];
//拿出数据字典,将数据字典转换为模型,并且将模型存放到apps数组中:
//两种方法:
<1> for 循环
for (int i = 0 ;i < array.count; i++)
{
//取出array 中存放的数据字典
NSDictionary * dict = array[i];
// 将数据字典转换为数据模型
ITApp *app = [ITApp ITAppWithDictionary:app];
//将数据模型添加到临时可变数组中
[appsArray addObject:app];
};
<2> Block
[array enumerateObjectsUsingBlock:^(id obj
NSUInteger idx,BOOL *stop){
//obj: 数组中存放的字典; idx :obj在数组中的位置
NSDictionary *dict = obj;
//将数据字典转换为数据模型
ITApp * app = [ITApp ITAppWithDictionary:dict];
//将数据模型添加到临时可变数组中
[appsArray addObject:app];
}];
//将数据模型添加到临时可变数组中
_apps = appsArray;
}
return _apps;
}
4 注意点:UITableView 的数据源方法;
-(UITableViewCell *)tableView:(UITableView *)tableViewcellRowAtIndexPath:(NSIndexPath *)indexPath{
必须返回一个: UITableViewCell
//调试的时候.用下面的这种方式写,不会报错
return [UITableViewCell new];
}
/*--------------------------- NSOperation综合案例: 2.下载图片/技术选择 ----------------------------*/
重点:
1.分析项目需求:
2.处理内存警告,优化用户体验;
3.技术选择,技术实施,代码编写.
4.Bug
{
项目需求:
<1> 下载图片
分析:
1>子线程下载图片,主线程显示图片
2>开启子线程有三种技术方案可供选择:
(1) NSThread
(2) GCD
(3) NSOperation 配合 NSOperationQueue使用
<2> 内存警告处理
分析:
接受到内存警告的时候,停止一切下载操作,防止闪退
<3> 用户体验
分析:
再与用户做 UI 交互的时候,最好暂停图片的下载;用户滚动结束之后,再继续下载图片
1.技术选择:(3) NSOperation 配合 NSOperationQueue使用
2.技术点实施
//<1> 用户开始滚动的时候,暂停下载操作;停止滚动之后,恢复下载操作
{
#pragma UIScrollerViewDelegate 代理协议
//开始滚动的时候调用
-(void)scrollerViewWillBeginDragging:(UIScrollerView *)scrollerView
{
NSLog(@“暂停下载---");
//暂停所有下载操作
[self.queue setSuspended:YES];
}
//滚动结束的时候调用
-(void)scrollerViewDidEndDragging:(UIScrollerView *)scrollerView willDecelerate:(BOOL)decelerate
{
NSLog(@“恢复下载==");
//恢复所有下载操作
[self.queue setSuspended:NO];
}
}
//<2> 接受到内存警告的时候,取消一切操作
{
//接受到内存警告的时候调用
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//取消一切下载操作
[self.queue cancelAllOperations];
}
}
//<3> 将下载图片的操作封装在 NSBlockOperation.最后将操作放在并发队列中,自动执行
{
__weak type(self)wself = self;
//定义下载操作
NSBlockOperation *o = [NSBlockOperation blockOperationWithBlock:^”{
//下载网络图片
UIImage *webImage = [wself downloadWebImage:app.icon];
//回到主线程显示图片
[NSOperationQueue mainQueue]addOperationWithBlock:^{
//显示图片
cell.imageView.image = webImage;
}];
}];
//将下载操作放在并发队列中,自动开启下载
[self.queue addOperation:op];
}
3.运行程序之后,发现3个 Bug
<1> 程序运行之后,图片不会直接显示出来,需要刷新之后才能显示(滚动/点击都会重绘UI)
<2> 图片错位问题
<3> 用户体验方面的Bug:只要滚动,图片就会重复下载,即使已经下载好的图片,也会重新下载(耗费流量,体验巨差,巨耗电)
/*------------------------------ NSOperation综合案例: 3.Bug 解决 ---------------------------------*/
重点.1.分析Bug产生的原因并解决Bug. 2.知识点回顾:如何防止一个url对应的图片重复下载?
{
Bug 产生的原因分析:
<1> 程序运行之后,图片不会直接显示出来,需要刷新之后才能显示(滚动/点击都会重绘 UI)
Bug产生的原因:UITableViewCell 中刚开始没有设置图片的 Frame ,图片下载完后,点击刷新之后,就会重新绘制, UITableViewCell,这样就会显示图片了
解决 Bug: 下载之前最好把图片的frame 绘制出来.比如,可以添加一张占位图片
//设置占位图片的代码
cell.imageView.image = [UIImage imageName:@“占位图片的名字"];
}
//图片错位问题
Bug产生的原因, UITableViewCell 的重用以及网络下延时产生的.
解决 Bug: 让数据控制视图(视图根据数据来显示出来)设置一个图片缓存 cell 中的图片来源于这个图片缓存
{
//设置图片缓存.
定义一个字典为图片缓存,保存下载好的图片(以图片的 url 作为 Key值,以下载好的图片为 Value)
//可以选择NSCache 代替字典作为缓存机制
//NSCache在内存紧张的时候,会自动释放一些资源(自动销毁图片,我们无法控制)
//如果使用字典,在接受到内存警告之后,需要手动释放资源
<2> 从缓存中取出 cell 对应的图片
cell 设置图片:根据 cell 的app.icon(url) 从字典中取出对应的图片
<3> 图片下载完毕之后刷新所在行的数据 的代码
[tableView reloadRowsAtIndexPaths:@[indexPath ] withRowAnimation:UITableViewRowAnimationNone];
??1?? :没必要刷新整个表格视图,刷新所在行额数据就可以了
}
<3> 用户体验方面的Bug :只要滚动,图片就会重复下载,即使已经下载好的图片,也会重新下载.(耗费流量,体验巨差,巨耗电)
Bug产生原因: 只要上下滚动,就会调用 - (UITableViewCell *)tableView:(UITableView*tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
这个方法.这个方法频繁调用导致下载操作一直创建.
解决 Bug:每次创建下载操作之前,最好先检查一下,下载操作是否存在,对于已经存在的操作,不要重复下载
//解决方法
{
<1> 设置操作缓存定义一个字典作为下载操作缓存,保存已经创建好的下载操作,(同样,以图片的 url 为Key值:以操作Operation 为Value)
<2> 从缓存中取出操作比较
每次重新创建下载操作之前,首先从下载操作缓存之中查看操作是否已经存在.如果存在,就不要再次创建:如果不存在,创建新的下载操作
<3> 防止操作缓存越存越大
图片下载成功之后,就下载操作就没有存在的意义了,应该及时清除缓存,防止下载操作缓存越来越大
}
关于NSCache Cache储藏保存的的意思
{
//可以选择 NSCache 代替字典作为缓存机制
NSCache 类结合了各种自动删除策略,以确保不会占用过多的系统内存.如果其他应用需要内存时,系统自动执行这些策略
NSCache是线程安全的,我们可以在不同的线程中添加/删除和查询缓存中的对象,而不需要锁定缓存区域
/*------------------------ NSOperation综合案例: 4.完善项目-添加沙盒缓存 -----------------------------*/
重点:1. 处理内存警告 2.添加沙盒缓存:
1> 由于添加了内存缓存机制(图片缓存和操作缓存) 在接受到内存警告的时候,最好释放内存缓存
将图片缓存在沙盒中,可以优化用户体验,以后每次展示图片,对于已经下载过的图片,就不需要重新下载
2.添加沙盒缓存.
<1> 认识沙盒
默认情况下,每个沙盒含有三个文件夹:
Documents 文件
Library 软件库
tmp
Documents :苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
Library : 存储程序的默认设置或其他状态信息
//Library/Caches: 存放缓存文件, iTunes 不会备份此目录,此目录下文件不会在应用退出删除
tmp:提供一个即时创建临时文件的地方
<2> 将图片写入沙盒:将文件存储在 Library/Caches路径
1>获取 /Caches路径
{
NSString * path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES).lastObject;
}
2>拼接文件路径
{
//拼接文件路径(path + app .lastPathComponent ),以url中图片的名作为名字
NSString *path = [path stringByAppendingPathComponent:app.icon.lastPathComponent];
}
3> 将 image 转换为二进制数据.//沙盒中不能直接存取图片数据
{
//将 UIImage 图片转换为二进制数据
NSData *data = UIImagePNGRepresentation(webImage);
}
4>将图片的二进制数据存入沙盒
{
//将图片的二进制数据存入沙盒,路径:file
[data writeToFile:file atomically:YES];
}
<3> 从沙盒中获取图片
1>获取 / Caches路径
2>拼接完整的图片文件路径
3>根据完整的图片文件路径获取图片
{
UIImage *image = [UIImage imageWithContentsOfFile:fileName];
}
}
/*----------------------------- NSOperation综合案例: 5.SDWebImage使用 ------------------------------*/
重点:1: SWWebImage
{
1.SDWebImage 简介:
SDWebImage 是一个开源的第三方库 ,他提供了UIImageView分类,以支持从远程服务器下载缓存图片的功能
<1> SDWebImageManager
在实际的运用中,我们并不直接使用SDWebImageDownloader类(网络图片下载类)以及SDImageCache类 (网络图片缓存类)来执行图片的下载及缓存.
为了方便用户的使用,SDWebImage提供了SDWebImageManager对象来管理图片的下载与缓存
我们经常用到的诸如UIImageView + WebCache等控件的分类都是基于SDWebImageManager对象的
该对象将一个下载器和一个图片缓存绑定在一起,并对外提供两个只读属性来获取他们
<2> UIImageView+WebCache
我们在使用SDWebImage 的时候,使用的最多的是UIImageView + WebCache中的针对的扩展方法,这些扩展方法将UIImageView与WebCache集成在一起,来让UIImageView对象拥有异步下载和缓存远程图片的能力
其中最核心的方法是:-sd_setImageWithURL:placeholderImage:options:progress:completed:其使用SDWebImageManager单例对象下载并缓存图片,完成后将图片赋值给UIImageViw对像那个的image属性.以使图片显示出来
//????????????????????
1>SDWebImage的默认缓存是多长时间?
答:一个星期
2>SDWebImage的默认最大并发数是多少?
答:6条
3>SDWebImage底层是怎么实现的?
答:cell下载图片思路 - 有沙盒缓存
3.SDWebImage常用方法;
1> 常用方法
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
2>SDWebImageOptions
* SDWebImageRetryFailed : 下载失败后,会自动重新下载
*SDWebImageLowPriority :当正在进行 UI 交互时,自动暂停内部的一些下载操作
*SDWebImageRetryFailed | SDWebImagePriority:拥有上面2个功能
3>内存处理: 当app接收到内存警告时
?????????????? 当app接收到内存警告
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
SDWebImageManager * mgr = [SDWebImageManager sharedManager];
//1.取消正在下载的操作
[mgr cancelAll];
//2. 清楚内存缓存
[mgr.imageCache clearMemory];
}
}
/*----------------------------- NSOperation综合案例: 6.自定义 NSOperation ----------------------------*/
{
自定义 NSOperation 的步骤;
重点 -(void)main 方法,在里面实现想执行的操作
重写 -(void)main 方法注意点:
1>自己创建自动释放池(如果异步操作,无法访问主线程的自动释放池)
2>经常通过 - (BOOL)isCancelled 方法检查操作是否取消,对取消做出相应
}
SDWebImage的使用
标签:
原文地址:http://www.cnblogs.com/R-X-L/p/4785164.html