cell下载图片的思路 --无沙盒(内存)缓冲

//
//  ViewController.m
//  06-表格图片下载
//
//  Created by jerry on 15/9/7.
//  Copyright (c) 2015年 jerry. All rights reserved.
//
/**
 *  代码重构
 *
 *  目的:1.如果代码太长,如果有一部分专门解决某一个问题,就单拿出来
 *  写的时候,如果思路清晰,能够一次性写完,但是也要注意重构
 *  时间长了,不好阅读
 *  重构代码,便于维护
 *
 *  重构的方法:
 *  如果有一部分代码专门解决某一个问题 ,就单拿出来
 *  1.新建一个方法-->单一功能拿出来
 *  2.参数-->需要传参数
 *  3.在原来的代码地方调用,抽取的方法。
 *  4.注意测试。
 *  5.注意if嵌套,在实际开发中,非常忌讳很深的嵌套,能优化的话最好优化,
 */
#import "ViewController.h"
#import "ZPApp.h"
@interface ViewController ()
// PLIST 文件数据容器
@property(nonatomic,copy)NSArray *appList;
// 全局队列
@property(nonatomic,strong)NSOperationQueue  *opQueue;

// 缓冲池 所有下载操作的缓冲池
@property(nonatomic,strong)NSMutableDictionary *operationCache;
// 所有图片的缓存
@property(nonatomic,strong)NSMutableDictionary *imageCache;
@end

@implementation ViewController

-(NSMutableDictionary *)imageCache
{
    if (_imageCache == nil) {
        _imageCache = [NSMutableDictionary dictionary];
    }
    return _imageCache;
}

-(NSMutableDictionary *)operationCache
{
    if (_operationCache == nil) {
        _operationCache = [NSMutableDictionary dictionary];
    }
    return _operationCache;
}
-(NSOperationQueue *)opQueue
{
    if (_opQueue == nil) {
        _opQueue = [[NSOperationQueue alloc]init];
    }
    return _opQueue;
}

 -(NSArray *)appList
{
    if (_appList == nil) {
        //获取文件路径
        NSString *str = [[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
        NSArray *fileArray = [NSArray arrayWithContentsOfFile:str];
        NSMutableArray *muArray = [NSMutableArray array];
        for ( NSDictionary *dict in fileArray) {
            ZPApp *app = [ZPApp appWithDict:dict];
            [muArray addObject:app];
        }
        _appList = muArray;
    }
    return _appList;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return  self.appList.count;
}
/**
 *  CELL里面的imageview属于懒加载
 *  问题1:如果网络比较慢,会比较卡
 *  解决办法:用异步下载
 *
 *  问题2:imageview没有frame
 *  解决办法:使用一个占位图,异步下载完成以后,不显示。(如果占位图比较大,自定义cell)
 *
 *  问题3:如果图片下载速度不一致,同时用户浏览快速滚动的时候,会因为cell的重用导致图片混乱。
 *  解决办法:MVC使用模型保持下载图像。再次刷新表格
 *
 *  问题4:在用户快速滚动的时候会重复添加下载操作到队列里。
 *  解决办法:建立一个下载操作的缓冲池,首先检查缓冲池里是否有当前这个下载操作,有的话就不用创建,没有的时候在下载。保证一个图片只对应一个下载操作。
 *
 *  问题5:将图像保存到模型里有缺点:
 *  优点:不用重复下载,利用mvc刷新表格,不会造成数据混乱。加载速度比较快
 *  缺点:内存消耗比较大,因为所有下载好的图像都会记录在模型里。如果数据比较多(20000),就会造成很大的内存警告
 *
 *  问题6:图像跟模型耦合性太强,导致清理内存非常困难
 *  解决办法:模型根图像分开,在控制器里边做缓存。
 *
 *  问题7:下载操作缓冲池,会越来越大,想办法清理
 *  解决办法:
 */
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建cell的标识
    static NSString *ID = @"AppCell";
    // 查找缓存池中有没有标识为ID的cell 如果有直接拿来用 如果没有创建一个
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
    }
    // 给cell 设置数据
    ZPApp *app = self.appList[indexPath.row];
    cell.textLabel.text = app.name;
    cell.detailTextLabel.text = app.download;
    // 判断模型里边是否有图像
    if ([self.imageCache objectForKey:app.icon])  { // --如果模型里面有图像,直接给cell的imageview赋值。
        NSLog(@"none");
//        cell.imageView.image = app.image;
        cell.imageView.image = self.imageCache[app.icon];
    }else{
    // 下载图片
//    [NSThread sleepForTimeInterval:0.5];
//    NSLog(@"正在下载.....");
        // 现实占位图
        cell.imageView.image = [UIImage imageNamed:@"user_default"];
#warning 从这里开始剪的代码
        // 下载图片
        [self downloadImage:indexPath];
        }
    // 异步执行下载,不需要等待,会直接执行return cell 也就是先初始化一个没有图片的cell 在表格上现实,后来把图片下载完成以后,给cell的imageview属性重新赋值。
    return cell;
}
/**
 *  下载图片
 *
 *  @param indexPath <#indexPath description#>
 */
- (void)downloadImage:(NSIndexPath *)indexPath
{
    ZPApp *app = self.appList[indexPath.row];
    // 如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有的话才需要 创建下载操作
#warning 缓冲池中的字典创建    key:是图片的url地址,因为这个地址是唯一的,而且是明确的。value:下载操作
    if (self.operationCache[app.icon]) {
        NSLog(@"已加入缓冲池,正在玩命下载中。。。");
        return;
    }
        // 缓冲池没有下载操作。

        // 异步下载图片
    NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{
        // 1.下载图片(二进制)
        NSURL *url = [NSURL URLWithString:app.icon];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *img = [UIImage imageWithData:data];
//            app.image = img; // 把下载好的图片保存到模型。
//            字典的赋值不能为nil,
//        将下载好的数据保存到集合里
        if (img) {
            [self.imageCache setObject:img forKey:app.icon];
        }
        // 将操作从操作缓冲池删除
        [self.operationCache removeObjectForKey:app.icon];
        // 更新ui
        [[NSOperationQueue mainQueue]addOperationWithBlock:^{
        //            cell.imageView.image = app.image;
        // 刷新当前行  reload会重新调用cell的初始化方法。重新判断模型里面是否有图像,有的话直接显示
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
            }];
        }];
        [self.opQueue addOperation:downloadOp];
        // 将当前图片的下载操作,存放到缓冲池中。
        [self.operationCache setObject:downloadOp forKey:app.icon];
}
/**
 *  真正开发中一定要注意这个方法
 */
-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    //当给了内存警告之后,一定要在这里做些内存清理的操作,如果不处理程序直接会被系统强制退出。
    // 清理图片内存
    [self.imageCache removeAllObjects];
    // 清理操作缓冲
    [self.operationCache removeAllObjects];
    // 取消下载队列里的人物
    [self.opQueue cancelAllOperations];
}
@end

model  .h

//
//  ZPApp.h
//  06-表格图片下载
//
//  Created by jerry on 15/9/7.
//  Copyright (c) 2015年 jerry. All rights reserved.
//
// xcode 6  pch
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ZPApp : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *icon;
@property(nonatomic,copy)NSString *download;
//@property(nonatomic,strong) UIImage  *image;
+(instancetype)appWithDict:(NSDictionary *)dict;

@end

.m

//
//  ZPApp.m
//  06-表格图片下载
//
//  Created by jerry on 15/9/7.
//  Copyright (c) 2015年 jerry. All rights reserved.
//

#import "ZPApp.h"

@implementation ZPApp
+(instancetype)appWithDict:(NSDictionary *)dict
{
    ZPApp *app =  [[self alloc]init];
    [app setValuesForKeysWithDictionary:dict];
    return app;
}
@end

plist文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>name</key>
        <string>植物大战僵尸</string>
        <key>icon</key>
        <string>http://p16.qhimg.com/dr/48_48_/t0125e8d438ae9d2fbb.png</string>
        <key>download</key>
        <string>10311万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>捕鱼达人2</string>
        <key>icon</key>
        <string>http://p19.qhimg.com/dr/48_48_/t0101e2931181bb540d.png</string>
        <key>download</key>
        <string>9982万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>保卫萝卜</string>
        <key>icon</key>
        <string>http://p17.qhimg.com/dr/48_48_/t012d281e8ec8e27c06.png</string>
        <key>download</key>
        <string>8582万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>找你妹</string>
        <key>icon</key>
        <string>http://p18.qhimg.com/dr/48_48_/t0184f949337481f071.png</string>
        <key>download</key>
        <string>5910万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>水果忍者</string>
        <key>icon</key>
        <string>http://p17.qhimg.com/dr/48_48_/t015f10076f95e27e74.png</string>
        <key>download</key>
        <string>5082万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>鳄鱼小顽皮</string>
        <key>icon</key>
        <string>http://p16.qhimg.com/dr/48_48_/t01885f5596e1d30172.png</string>
        <key>download</key>
        <string>3918万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>神偷奶爸</string>
        <key>icon</key>
        <string>http://p19.qhimg.com/dr/48_48_/t0164ad383c622aabef.png</string>
        <key>download</key>
        <string>3681万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>时空猎人</string>
        <key>icon</key>
        <string>http://p17.qhimg.com/dr/48_48_/t017bc3cfcf3981b197.png</string>
        <key>download</key>
        <string>3645万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>愤怒的小鸟</string>
        <key>icon</key>
        <string>http://p18.qhimg.com/dr/48_48_/t012fea7312194537c2.png</string>
        <key>download</key>
        <string>3552万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>滑雪大冒险</string>
        <key>icon</key>
        <string>http://p18.qhimg.com/dr/48_48_/t01e61cbba53fb9eb82.png</string>
        <key>download</key>
        <string>3487万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>爸爸去哪儿</string>
        <key>icon</key>
        <string>http://p18.qhimg.com/dr/48_48_/t0108c33d3321352682.png</string>
        <key>download</key>
        <string>3117万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>我叫MT </string>
        <key>icon</key>
        <string>http://p17.qhimg.com/dr/48_48_/t01077fd80ffb5c8740.png</string>
        <key>download</key>
        <string>2386万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>3D终极狂飙</string>
        <key>icon</key>
        <string>http://p17.qhimg.com/dr/48_48_/t01f55acd4a3ed024eb.png</string>
        <key>download</key>
        <string>2166万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>杀手2</string>
        <key>icon</key>
        <string>http://p16.qhimg.com/dr/48_48_/t018f89d6e0922f75a1.png</string>
        <key>download</key>
        <string>1951万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>俄罗斯方块</string>
        <key>icon</key>
        <string>http://p0.qhimg.com/dr/48_48_/t0183a670f1dbff380f.png</string>
        <key>download</key>
        <string>1290万</string>
    </dict>
    <dict>
        <key>name</key>
        <string>刀塔传奇</string>
        <key>icon</key>
        <string>http://p16.qhimg.com/dr/48_48_/t01c3f62a27c3de7af5.png</string>
        <key>download</key>
        <string>1249万</string>
    </dict>
</array>
</plist>
时间: 2024-10-11 18:44:17

cell下载图片的思路 --无沙盒(内存)缓冲的相关文章

cell下载图片思路 – 无沙盒缓存

cell下载图片思路 – 无沙盒缓存 /** *  1.会阻塞主线程 - 影响用户体验 *  2.重复下载 - 浪费流量,浪费时间,影响用户体验 */ // 保证:1张图片只下载1次 /** * 所有的应用数据 */ @property(nonatomic,strong)NSMutableArray*apps; /** * 存放所有下载操作的队列 */ @property(nonatomic,strong)NSOperationQueue*queue; /** * 存放所有的下载操作(url是k

iOS开发实践之cell下载图片(NSOperation)

滚动列表cell的图片从服务器上下载显示,利用多线程和缓存技术 高效下载显示图片. cell下载图片思路: 1.定义images字典存放下载后的图片(图片下载url作为key,图片作为value)cell图片先去images字典中找,没有就往下(沙盒中查找). 2.查找沙盒是否存在,若存在就设置cell图片,否则显示占位图片(增强体验感)并开启线程下载图片. 3.定义字典operations存放所有的下载操作(url是key,operation对象是value).判断下载操作是否存在,若存在 说

无沙盒缓存原理

无沙盒缓存原理:主要由两部分组成 1.内存图片缓存 2.内存操作缓存

iOS开发实践之cell下载图片(自定义NSOperation)

上一篇文章的下载图片操作都放在了block中,当遇到复杂的操作,一堆的代码放在block中 ,很明显这不是明智的选择,代码显得很臃肿. 因此,把线程操作放到自定义NSOperation中. 自定义NSOperation的步骤:继承NSOperation.重写- (void)main方法,在里面实现想执行的任务. 重写- (void)main方法的注意点: 1.自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池). 2.经常通过- (BOOL)isCancelled方法检测操作是否

ios -- cell的图片下载

1.面试题 1> 如何防止一个url对应的图片重复下载 * “cell下载图片思路 – 有沙盒缓存” 2> SDWebImage的默认缓存时长是多少? * 1个星期 3> SDWebImage底层是怎么实现的? * 上课PPT的“cell下载图片思路 – 有沙盒缓存” 2.SDWebImage 1> 常用方法 - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder; - (voi

NSOperation下载图片-01

无沙盒缓存 1 #import "HMAppViewController.h" 2 #import "HMApp.h" 3 4 @interface HMAppViewController () 5 /** 6 * 模型数组 7 */ 8 @property (nonatomic, strong) NSArray *apps; 9 10 /** 11 * 存储icon的url的字典 12 */ 13 @property (nonatomic, strong) NSM

oppo手机使用应用沙盒动态修改局域网ip参数

较早前文章介绍了怎么在安卓手机上安装激活XPosed框架,XPosed框架的牛逼之处功能大伙都知道,能不修改Apk的前提下,修改系统内部的参数,比如在某些应用情景,大伙需要修改手机的某个系统参数,这时就需要使用XPosed以及相关模块功能来完成.下面内容总计一下具体xposed框架的下载和框架模块应用沙盒的使用流程,成功激活并准确修改局域网ip参数.首先,具体XPOSED框架我们可以在软件作者官方网站了解具体说明.https://repo.XPOSED.info/第一步,下载并安装激活Xpose

vivo手机使用应用沙盒一键修改位置信息

前面文章介绍了怎么样在安卓手机上安装激活xposed框架,xposed框架的极强的功能各位都知道,能够不修改应用程序的前提下,修改系统内部的参数,比如在某些应用需要,各位需要修改手机的某个系统参数,这时就需要使用xposed以及相关模块功能来完成. 这里归纳一下具体xposed框架的下载和框架模块应用沙盒的使用流程,成功激活并正确修改位置参数. 首先,对于XPosed框架大伙可以在作者官方网址了解详细资料.https://repo.XPosed.info/ 第一步,下载并安装激活Xposed框架

oppo手机使用应用沙盒动态修改系统版本参数

较早前文章介绍了怎么样在安卓手机上安装激活Xposed框架,Xposed框架的牛逼之处功能我们都清楚,能不修改APK的前提下,修改系统内核的参数,好比在某些应用范畴,我们需要修改手机的某个系统参数,这种情况就需要使用Xposed以及相关模块功能来实现.在这里记录一下具体xposed框架的下载和框架模块应用沙盒的使用流程,成功激活并正确修改系统版本参数.首先,具体XPosed框架各位可以在作者官方网站了解详细介绍.https://repo.XPosed.info/第一步,下载并安装激活xposed