• 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>
  • 相关阅读:
    计算中文或全角字符串的长度
    day25 python学习 继承,钻石继承 多态
    day25 python学习 继承,钻石继承
    day24 python学习 类 画元,命名空间作用域,组合,人狗大战升级
    第四周经典问题收集
    day23 python学习 类 人狗大战
    day20 python sys os time json pickl 正则
    python 常见的内置函数
    encode decode enumerate
    3.易错点和新要掌握的内容
  • 原文地址:https://www.cnblogs.com/pengpengzhang/p/4788650.html
Copyright © 2020-2023  润新知