如何实现从网络获取图片的缓存机制

前言

  在iOS开发中从网络加载图片是一个比较值得思考的问题,因为你要考虑用户的体验,这其实包括流畅度,以及用户的流量考虑,那么今天我就来简单的说点这方面知识。

具体实现:

  说到缓存就可以分为内存缓存和沙盒缓存,内存缓存的话就是用简单的用一个字典来记录下载的图片。

  今天的环境就是从网络下载一些图片给tableview的imageView的image赋值,SAMApp是模型类,icon是url.

  1.定义几个属性,具体如下

/** 所有数据 */
@property (nonatomic, strong) NSArray *apps;

/** 内存缓存的图片 */
@property (nonatomic, strong) NSMutableDictionary *images;

/** 记录正在下载的任务 */
@property (nonatomic, strong) NSMutableDictionary *operations;

/** 队列对象 */
@property (nonatomic, strong) NSOperationQueue *queue;

  2.判断内存中有没有值,这里面把url当做key来从字典中取值,相当于内存中取值,如何有值那就直接给imageView的image赋值

// 从内存中取出图片
    UIImage *image = self.images[app.icon];

    if (image) {
        // 内存里面有值
        cell.imageView.image = image;

  

  3.如何内存中没有值,那么就去沙盒中检查有否有需要的图片,这里面把url当作最后的路径目录

// 获取cache目录
        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory , NSUserDomainMask, YES) firstObject];

        // 获取文件名
        NSString *filePath = [app.icon lastPathComponent];

        // 计算出全部路径
        NSString *file = [cachePath stringByAppendingString:filePath];

        // 加载沙盒中的文件数据
        NSData *data = [NSData dataWithContentsOfFile:file];

  4.如果以上情况都没有,这时应该添加占位视图,如果你是自定义的cell可能不需要,但是系统的UITableViewCell是需要的,要不然需要拖动之后才会显示图片。

  5.这时我们就应该开启线程从网上下载图片,如果只是简单的开启线程下载,这个过程会出现图片的位置不对,搬动刷新之后才正常的状况,这是由于cell的重利用导致的,当图片正在下载的时候,你这个cell可能重利用到下一个位置上去了,然后正好下载结束就会产生错误的图片加载。如何解决呢?

  解决的方法其实很简单,因为我们下载的每一个图片我们都需要去开起一个NSOperation,这时我们用url为key的字典来记录这些正在下载的operation.每次先去这些operation里面取,如果有说明是正在下载,那么就不开起线程,如果没有在开起。

  没有的情况下,说明我们需要开起线程,在这种情况下我们需要注意一种情况,就是如何下载失败的情况下我们就要反这个key从字典里面移除,要不然这一个图片就会不能再下载。

核心代码:

 if (image) {
        // 内存里面有值
        cell.imageView.image = image;
    } else {
        //从沙盒里面取
        // 获取cache目录
        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory , NSUserDomainMask, YES) firstObject];

        // 获取文件名
        NSString *filePath = [app.icon lastPathComponent];

        // 计算出全部路径
        NSString *file = [cachePath stringByAppendingString:filePath];

        // 加载沙盒中的文件数据
        NSData *data = [NSData dataWithContentsOfFile:file];
        // 沙盒里面是否有数据
        if (data) {
            // 有数据直接给图片赋值
            UIImage *image = [UIImage imageWithData:data];
            cell.imageView.image = image;

            // 重新存到内存里面
            self.images[app.icon] = image;
        } else {
            // 占位视图
            cell.imageView.image = [UIImage imageNamed:@"1"];

            NSOperation *operation = self.operations[app.icon];

            // 该任务是否正在下载
            if (operation == nil) {

                // 没有下载,创建
                operation  =  [NSBlockOperation blockOperationWithBlock:^{

                    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];

                    if (data == nil) {

                        [self.operations removeObjectForKey:app.icon];
                        return ;
                    }

                    UIImage *image = [UIImage imageWithData:data];
                    // 记录到内存字典
                    self.images[app.icon] = image;

                    // 回到主线程显示图片
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        // 刷新指定行的数据
                        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
                    }];

                    // 把二进制文件写入沙盒
                    [data writeToFile:file atomically:YES];

                    // 下载任务完成,移除记录的操作
                    [self.operations removeObjectForKey:app.icon];

                }];

                //加入队列
                [self.queue addOperation:operation];

                // 记录正在下载的操作
                self.operations[app.icon] = operation;
            }
        }

    }

  

  

时间: 2024-09-30 19:05:26

如何实现从网络获取图片的缓存机制的相关文章

Android LazyList 从网络获取图片并缓存

原文地址   本文内容 环境 演示 LazyList 从网络获取图片并缓存 参考资料 本文是 Github 上的一个演示,通过网络获取歌手专辑的缩略图,并显示在 ListView 控件中.该演示具备将缩略图缓存到手机外存的功能,所以叫"Lazy",这样就不用每次都通过网络重新获取. 该演示仅仅是获得缩略图,但在另一篇文章中,作者根据这个 LazyList,做了一个相对完整的演示(包括歌曲名称.歌手名.时长.缩略图等信息),如图 3 所示. 环境 Windows 2008 R2 64 位

Android ListView从网络获取图片及文字显示

从网络获取图片以及文本来显示.事实上,一般是先获取Josn或sml数据,然后解释显示.我们先从网上获取xml,然后对其进行解析,最后显示在ListView上.具体步骤: 客户端发出请求,获取xml 客户端异步解析xml ListView将解析完的数据显示 一.Android客户端 (1)xml布局文件         mainxml,就是一个ListView. [java] view plaincopy <?xml version="1.0" encoding="utf

android从网络获取图片

http://blog.csdn.net/wangjinyu501/article/details/8219317 http://www.cnblogs.com/JerryWang1991/archive/2012/03/09/2388312.html http://blog.csdn.net/liuhe688/article/details/6532519 http://blog.csdn.net/abc5382334/article/details/17097633 http://www.t

Android 通过网络获取图片的源码

将开发过程中经常用到的内容做个备份,如下的资料是关于Android 通过网络获取图片的的内容. package com.netimg; import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.view.View;import android.view.View.OnClickLis

基于Android4.0ListView从网络获取图片文字资源显示

平时的一些Android学习视频中,他们都是基于Android的去使用ListView,我看到都是会在UI线程中去访问网络获取数据,但是这在Android4.0之后是行不通的. 首先我们来理一下思绪: 我们需要从网络上下载一份xml数据,里面包含了需要显示的文字和图片路径.所以我们首先需要的就是先去下载数据,下载数据完成之后再在Adapter中显示图片的时候去下载图片,然后显示出来.这是基本的思路.但是做着做着会发现一些问题,比如,我们如何能保证数据下载完全,才去绑定适配器和数据他们.然后假如我

android ViewPager实现的轮播图广告自定义视图,网络获取图片和数据

public class SlideShowAdView extends FrameLayout { //轮播图图片数量    private static int IMAGE_COUNT = 3;    //自动轮播的时间间隔    private final static int TIME_INTERVAL = 5;    //自动轮播启用开关    private final static boolean isAutoPlay = false;       //自定义轮播图的资源ID   

Swift之从网络获取图片

// //  ViewController.swift //  项目之获取图片 // //  Created by 悦兑科技 on 15/2/4. //  Copyright (c) 2015年 BSY. All rights reserved. // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() /** *  初始化URL并且获取图片

Android--从网络获取图片的三种方法

android中获取网络图片是一件耗时的操作,如果直接获取有可能会出现应用程序无响应(ANR:Application Not Responding)对话框的情况.对于这种情况,一般的方法就是耗时操作用线程来实现.下面列三种获取url图片的方法: 1.直接获取:(容易:ANR,不建议) mImageView = (ImageView)this.findViewById(R.id.imageThreadConcept) ;Drawable drawable = loadImageFromNetwor

android网络获取图片并保存在本地

获取网络上的图片有三步: 一.设置连接网络的权限和写入读取SD卡的权限.二.网络访问获得数据流. 三.在SD卡中创建文件夹将数据流转成图片格式存储. 注意:response.getEntity().getContent()方法,而此方法只能调用一次.否则会报错:java.lang.IllegalStateException: Content has been consumed. manifest.xml 赋予权限,注意:在<application...>application>前添加 &