ImageCache 网络图片缓存

1、ImageCache

  • 使用内存缓存方式:


  • 使用沙盒缓存方式:


  • 使用网络图片第三方库方式:

    • SDWebImage:

      • iOS 中著名的网络图片处理框架
      • 包含的功能:图片下载、图片缓存、下载进度监听、gif 处理等等
      • 用法极其简单,功能十分强大,大大提高了网络图片的处理效率
      • 国内超过 90% 的 iOS 项目都有它的影子

      • 1、图片文件缓存的时间有多长?

        • 1 周

          1
          2
          3
          _maxCacheAge = kDefaultCacheMaxCacheAge;                                    // - (id)initWithNamespace: diskCacheDirectory:

          static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week SDImageCache.m
      • 2、SDWebImage 的内存缓存是用什么实现的?

        • NSCache
      • 3、SDWebImage 的最大并发数是多少?

        • 是程序固定死了,可以通过属性进行调整!

          1
          _downloadQueue.maxConcurrentOperationCount = 6;                             // SDWebImageDownloader.m   - (id)init
      • 4、网络访问超时时长

        • iOS 开发中,默认的访问时长是 1 分钟,SDWebImage 中是 15 秒。

          1
          _downloadTimeout = 15.0;                                                    // SDWebImageDownloader.m   - (id)init
      • 5、SDWebImage 支持动图吗?GIF

        • 支持

          1
          2
          #import <ImageIO/ImageIO.h>                                                 // UIImage+GIF.m
          [UIImage animatedImageWithImages:images duration:duration];
      • 6、SDWebImage 是如何区分不同格式的图像的

        • 根据图像数据第一个字节来判断的!

          1
          2
          3
          4
          5
          // NSData+ImageContentType.m    + (NSString *)sd_contentTypeForImageData:

          PNG:0x89 image/png ,压缩比没有 JPG 高,但是无损压缩,解压缩性能高,苹果推荐的图像格式!
          JPG:0xFF image/jpeg,压缩比最高的一种图片格式,有损压缩!最多使用的场景,照相机!解压缩的性能不好!
          GIF:0x47 image/gif ,序列桢动图,特点:只支持 256 种颜色!最流行的时候在 19981999,有专利的!
      • 7、SDWebImage 缓存图片的名称是怎么确定的!

        • md5

        • 如果单纯使用 文件名保存,重名的几率很高!

        • 使用 MD5 的散列函数!对完整的 URL 进行 md5,结果是一个 32 个字符长度的字符串!
      • 8、SDWebImage 的内存警告是如何处理的!

        • 利用通知中心观察

        • UIApplicationDidReceiveMemoryWarningNotification 接收到内存警告的通知

        • 执行 clearMemory 方法,清理内存缓存!

        • UIApplicationWillTerminateNotification 接收到应用程序将要终止通知

        • 执行 cleanDisk 方法,清理磁盘缓存!

        • UIApplicationDidEnterBackgroundNotification 接收到应用程序进入后台通知

        • 执行 backgroundCleanDisk 方法,后台清理磁盘!

        • 通过以上通知监听,能够保证缓存文件的大小始终在控制范围之内!

        • clearDisk 清空磁盘缓存,将所有缓存目录中的文件,全部删除! 实际工作,将缓存目录直接删除,再次创建一个同名空目录!
      • bug:

        • SDWebImage 中,一旦内存警告,清理了内存之后,之后所有的图片都是从沙盒加载的。

        • 原因:NSCache 中一旦调用了 removeAllObjects,就无法给 cache 添加对象。关于 NSCache 的内存管理,交给他自己就行!

2、自定义内存缓存方式

  • Objective-C

    • AppInfoModel.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @interface AppInfoModel : NSObject

      /// 标题名称
      @property (nonatomic, strong) NSString *name;

      /// 下载数量
      @property (nonatomic, strong) NSString *download;

      /// 图片地址
      @property (nonatomic, strong) NSString *icon;

      /// 声明工厂方法,数据源初始化方法
      + (instancetype)appInfoModelWithDict:(NSDictionary *)dict;

      @end
    • AppInfoModel.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // 实现工厂方法
      + (instancetype)appInfoModelWithDict:(NSDictionary *)dict {

      id obj = [[self alloc] init];

      [obj setValuesForKeysWithDictionary:dict];

      return obj;
      }
    • AppInfoCell.h

      1
      2
      3
      4
      5
      6
      7
      @interface AppInfoCell : UITableViewCell

      @property (nonatomic, weak) IBOutlet UILabel *nameLabel;
      @property (nonatomic, weak) IBOutlet UILabel *downloadLabel;
      @property (nonatomic, weak) IBOutlet UIImageView *iconImageView;

      @end
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      /// 表格数据源
      @property (nonatomic, strong) NSArray *dataSourceArray;

      /// 图片下载队列
      @property (nonatomic, strong) NSOperationQueue *downloadQueue;

      /// 下载缓冲池
      @property (nonatomic, strong) NSMutableDictionary *downloadQueueCache;

      /// 图片缓冲池
      @property (nonatomic, strong) NSMutableDictionary *imageCache;

      /// 图片下载地址黑名单
      @property (nonatomic, retain) NSMutableArray *urlBlackList;

      // 懒加载

      - (NSArray *)dataSourceArray {
      if (_dataSourceArray == nil) {
      NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]];

      NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:array.count];
      [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [arrayM addObject:[AppInfoModel appInfoModelWithDict:obj]];
      }];
      _dataSourceArray = [arrayM copy];
      }
      return _dataSourceArray;
      }

      - (NSOperationQueue *)downloadQueue {
      if (_downloadQueue == nil) {
      _downloadQueue = [[NSOperationQueue alloc] init];
      }
      return _downloadQueue;
      }

      - (NSMutableDictionary *)downloadQueueCache {
      if (_downloadQueueCache == nil) {
      _downloadQueueCache = [[NSMutableDictionary alloc] init];
      }
      return _downloadQueueCache;
      }

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

      - (NSMutableArray *)urlBlackList {
      if (_urlBlackList == nil) {
      _urlBlackList = [[NSMutableArray alloc] init];
      }
      return _urlBlackList;
      }

      // 表格视图数据源方法

      - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return self.dataSourceArray.count;
      }

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

      AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      cell.nameLabel.text = dataModel.name;
      cell.downloadLabel.text = dataModel.download;

      // 判断图片缓存池中是否有相应的图片
      if (self.imageCache[dataModel.icon] != nil) {

      // 从缓存池中取出图片显示在 Cell 上
      cell.iconImageView.image = self.imageCache[dataModel.icon];
      } else {

      // 从网络异步下载图片
      [self downloadImageWithIndexPath:indexPath];
      }

      return cell;
      }

      - (void)downloadImageWithIndexPath:(NSIndexPath *)indexPath {

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      // 判断下载缓冲池中是否存在当前下载操作
      if (self.downloadQueueCache[dataModel.icon] != nil) {
      return;
      }

      // 判断图片地址是否在黑名单中
      if ([self.urlBlackList containsObject:dataModel.icon]) {
      return;
      }

      // 创建异步下载图片操作
      NSBlockOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{

      UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:dataModel.icon]]];

      // 下载完成从下载缓冲池中删除当前下载操作
      [self.downloadQueueCache removeObjectForKey:dataModel.icon];

      // 添加黑名单记录
      if (image == nil && ![self.urlBlackList containsObject:dataModel.icon]) {
      [self.urlBlackList addObject:dataModel.icon];
      }

      // 主线程跟新 UI
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{

      if (image != nil) {

      // 将下载完成的图片保存到图片缓冲池中
      [self.imageCache setObject:image forKey:dataModel.icon];

      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
      }
      }];
      }];

      // 将当前下载添加到下载缓冲池中
      [self.downloadQueueCache setObject:downloadOperation forKey:dataModel.icon];

      // 开始异步下载图片
      [self.downloadQueue addOperation:downloadOperation];
      }

      // 内存警告
      /*
      日常上课通常就直接删除,但是在工作后,必须要处理!不处理后果很严重,第一次内存警告如果不处理,就没有第二次的机会了,就直接被闪退了
      */

      - (void)didReceiveMemoryWarning {

      [super didReceiveMemoryWarning];

      // 清理缓冲池
      [self.downloadQueueCache removeAllObjects];
      [self.imageCache removeAllObjects];

      // 取消下载操作,等用户再滚动表格,调用数据源方法,又能够自动下载
      [self.downloadQueue cancelAllOperations];
      }
  • Swift

    • AppInfo.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      class AppInfo: NSObject {

      var name: String!
      var icon: String!
      var download: String!

      class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject {
      let obj: AnyObject = self.init()

      obj.setValuesForKeysWithDictionary(dict)

      return obj
      }

      required override init() {
      super.init()
      }
      }
    • AppInfoCell.swift

      1
      2
      3
      4
      5
      6
      class AppInfoCell: UITableViewCell {

      @IBOutlet weak var iconView: UIImageView!
      @IBOutlet weak var nameLabel: UILabel!
      @IBOutlet weak var downLabel: UILabel!
      }
    • ViewController.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      // 懒加载

      // 数据源
      lazy var dataSourceArray: [AnyObject] = {
      var dataArray: [AnyObject] = Array()

      let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!)
      array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer<ObjCBool>) in
      dataArray.append(AppInfoModel.AppInfoWithDict(obj as! [String : AnyObject]))
      }
      return dataArray
      }()

      // 下载队列
      lazy var downloadQueue: NSOperationQueue = {
      var tmp:NSOperationQueue = NSOperationQueue()
      return tmp
      }()

      // 下载缓冲池
      lazy var downloadQueueCache: [String:NSBlockOperation] = {
      var tmp:[String:NSBlockOperation] = Dictionary()
      return tmp
      }()

      // 图片缓冲池
      lazy var imageCache: [String: UIImage] = {
      var tmp:[String:UIImage] = Dictionary()
      return tmp
      }()

      // 图片下载地址黑名单
      lazy var urlBlackList: [String] = {
      var tmp:[String] = Array()
      return tmp
      }()

      // 表格视图数据源方法

      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return self.dataSourceArray.count
      }

      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

      let cell:AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      cell.nameLabel.text = dataModel.name
      cell.downLabel.text = dataModel.download

      // 判断图片缓存池中是否有相应的图片
      if self.imageCache[dataModel.icon] != nil {

      // 从缓存池中取出图片显示在 Cell 上
      cell.iconView.image = self.imageCache[dataModel.icon]
      } else {

      // 从网络异步下载图片
      self.downloadImageWithIndexPath(indexPath)
      }
      return cell
      }

      func downloadImageWithIndexPath(indexPath:NSIndexPath) {

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      // 判断下载缓冲池中是否存在当前下载操作
      if self.downloadQueueCache[dataModel.icon] != nil {
      return
      }

      // 判断图片地址是否在黑名单中
      if self.urlBlackList.contains(dataModel.icon) {
      return
      }

      // 创建异步下载图片操作
      let downloadOperation = NSBlockOperation {

      let image:UIImage? = UIImage(data: NSData(contentsOfURL: NSURL(string: dataModel.icon)!)!)

      // 下载完成从下载缓冲池中删除当前下载操作
      self.downloadQueueCache.removeValueForKey(dataModel.icon)

      // 添加黑名单记录
      if image == nil && !self.urlBlackList.contains(dataModel.icon) {

      self.urlBlackList.append(dataModel.icon)
      }

      // 主线程跟新 UI
      NSOperationQueue.mainQueue().addOperationWithBlock({

      if image != nil {

      // 将下载完成的图片保存到图片缓冲池中
      self.imageCache[dataModel.icon] = image

      self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
      }
      })
      }

      // 将当前下载添加到下载缓冲池中
      self.downloadQueueCache[dataModel.icon] = downloadOperation

      // 开始异步下载图片
      self.downloadQueue.addOperation(downloadOperation)
      }

      // 内存警告

      override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()

      self.downloadQueueCache.removeAll()
      self.imageCache.removeAll()

      self.downloadQueue.cancelAllOperations()
      }

3、自定义沙盒缓存方式

  • Objective-C

    • AppInfoModel.h
    • AppInfoModel.m
    • AppInfoCell.h

      • 与上边一样
    • NSString+BundlePath.h

      1
      2
      ///  拼接缓存目录
      - (NSString *)appendCachePath;
    • NSString+BundlePath.m

      1
      2
      3
      4
      - (NSString *)appendCachePath {
      NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
      return [dir stringByAppendingPathComponent:self.lastPathComponent];
      }
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      // 懒加载

      与上边一样

      // 表格视图数据源方法

      - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return self.dataSourceArray.count;
      }

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

      AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      cell.nameLabel.text = dataModel.name;
      cell.downloadLabel.text = dataModel.download;

      // 判断图片缓存池中是否有相应的图片
      if (self.imageCache[dataModel.icon] != nil) {

      // 从缓存池中取出图片显示在 Cell 上
      cell.iconImageView.image = self.imageCache[dataModel.icon];

      } else {

      // 从沙盒加载图片
      UIImage *image = [UIImage imageWithContentsOfFile:[dataModel.icon appendCachePath]];

      if (image != nil) {

      cell.iconImageView.image = image;
      self.imageCache[dataModel.icon] = image;

      } else {

      // 从网络异步下载图片
      [self downloadImageWithIndexPath:indexPath];
      }
      }

      return cell;
      }

      - (void)downloadImageWithIndexPath:(NSIndexPath *)indexPath {

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      // 判断下载缓冲池中是否存在当前下载操作
      if (self.downloadQueueCache[dataModel.icon] != nil) {
      return;
      }

      // 判断图片地址是否在黑名单中
      if ([self.urlBlackList containsObject:dataModel.icon]) {
      return;
      }

      // 创建异步下载图片操作
      NSBlockOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{

      NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:dataModel.icon]];
      UIImage *image = [UIImage imageWithData:imageData];

      // 下载完成从下载缓冲池中删除当前下载操作
      [self.downloadQueueCache removeObjectForKey:dataModel.icon];

      // 添加黑名单记录
      if (image == nil && ![self.urlBlackList containsObject:dataModel.icon]) {
      [self.urlBlackList addObject:dataModel.icon];
      }

      if (image != nil) {

      // 将图像写入沙盒
      [imageData writeToFile:[dataModel.icon appendCachePath] atomically:YES];
      }

      // 主线程跟新 UI
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{

      if (image != nil) {

      // 将下载完成的图片保存到图片缓冲池中
      [self.imageCache setObject:image forKey:dataModel.icon];

      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
      }
      }];
      }];

      // 将当前下载添加到下载缓冲池中
      [self.downloadQueueCache setObject:downloadOperation forKey:dataModel.icon];

      // 开始异步下载图片
      [self.downloadQueue addOperation:downloadOperation];
      }

      // 内存警告

      与上边一样
  • Swift

    • AppInfo.swift
    • AppInfoCell.swift

      • 与上边一样
    • String+BundlePath.swift

      1
      2
      3
      4
      5
      6
      7
      8
      public func appendCachePath() -> String? {
      let dir: String? = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true).last
      if (dir != nil) {
      return dir! + "/" + (self as NSString).lastPathComponent
      } else {
      return nil
      }
      }
    • ViewController.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      // 懒加载

      与上边一样

      // 表格视图数据源方法

      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return self.dataSourceArray.count
      }

      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

      let cell: AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      cell.nameLabel.text = dataModel.name
      cell.downLabel.text = dataModel.download

      // 判断图片缓存池中是否有相应的图片
      if self.imageCache[dataModel.icon] != nil {

      // 从缓存池中取出图片显示在 Cell 上
      cell.iconView.image = self.imageCache[dataModel.icon]

      } else {

      // 从沙盒加载图片
      let image = UIImage(contentsOfFile: dataModel.icon.appendCachePath()!)

      if (image != nil) {

      cell.iconView.image = image
      self.imageCache[dataModel.icon] = image

      } else {

      // 从网络异步下载图片
      self.downloadImageWithIndexPath(indexPath)
      }
      }

      return cell
      }

      func downloadImageWithIndexPath(indexPath:NSIndexPath) {

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      // 判断下载缓冲池中是否存在当前下载操作
      if self.downloadQueueCache[dataModel.icon] != nil {

      return
      }

      // 判断图片地址是否在黑名单中
      if self.urlBlackList.contains(dataModel.icon) {

      return
      }

      // 创建异步下载图片操作
      let downloadOperation = NSBlockOperation {

      let imageData: NSData? = NSData(contentsOfURL: NSURL(string: dataModel.icon)!)

      let image:UIImage? = UIImage(data: imageData!)

      // 下载完成从下载缓冲池中删除当前下载操作
      self.downloadQueueCache.removeValueForKey(dataModel.icon)

      // 添加黑名单记录
      if image == nil && !self.urlBlackList.contains(dataModel.icon) {

      self.urlBlackList.append(dataModel.icon)
      }

      if image != nil {

      // 将图像写入沙盒
      imageData!.writeToFile(dataModel.icon.appendCachePath()!, atomically: true)

      print(dataModel.icon.appendCachePath()!)
      }

      // 主线程跟新 UI
      NSOperationQueue.mainQueue().addOperationWithBlock({

      if image != nil {

      // 将下载完成的图片保存到图片缓冲池中
      self.imageCache[dataModel.icon] = image

      self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
      }
      })
      }

      // 将当前下载添加到下载缓冲池中
      self.downloadQueueCache[dataModel.icon] = downloadOperation

      // 开始异步下载图片
      self.downloadQueue.addOperation(downloadOperation)
      }

      // 内存警告

      与上边一样

4、仿 SDWebImage 缓存方式

  • Objective-C

    • AppInfoModel.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @interface AppInfoModel : NSObject

      /// 标题名称
      @property (nonatomic, strong) NSString *name;

      /// 下载数量
      @property (nonatomic, strong) NSString *download;

      /// 图片地址
      @property (nonatomic, strong) NSString *icon;

      /// 从 Plist 加载 AppInfo
      + (NSArray *)loadPList;

      @end
    • AppInfoModel.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      + (NSArray *)loadPList {

      NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]];

      NSMutableArray *plist = [NSMutableArray arrayWithCapacity:array.count];
      [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

      id model = [[self alloc] init];
      [model setValuesForKeysWithDictionary:obj];

      [plist addObject:model];
      }];

      return plist;
      }
    • AppInfoCell.h

      1
      2
      3
      4
      5
      6
      7
      @interface AppInfoCell : UITableViewCell

      @property (nonatomic, weak) IBOutlet UILabel *nameLabel;
      @property (nonatomic, weak) IBOutlet UILabel *downloadLabel;
      @property (nonatomic, weak) IBOutlet UIImageView *iconImageView;

      @end
    • NSString+BundlePath.h

      1
      2
      ///  拼接缓存目录
      - (NSString *)appendCachePath;
    • NSString+BundlePath.m

      1
      2
      3
      4
      - (NSString *)appendCachePath {
      NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
      return [dir stringByAppendingPathComponent:self.lastPathComponent];
      }
    • WebImageOperation.h

      1
      2
      3
      4
      5
      6
      @interface WebImageOperation : NSOperation

      /// 实例化 web 图像操作
      + (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *image))completion;

      @end
    • WebImageOperation.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      /// 下载图片的 URL
      @property (nonatomic, copy) NSString *urlStr;

      /// 下载完成的回调
      @property (nonatomic, copy) void (^completion) (UIImage *image);

      + (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *))completion {

      WebImageOperation *imageOperation = [[self alloc] init];

      imageOperation.urlStr= urlString;
      imageOperation.completion = completion;

      return imageOperation;
      }

      // 操作加入队列后会自动执行该方法
      - (void)main {
      @autoreleasepool {

      if (self.isCancelled) return;

      NSURL *url = [NSURL URLWithString:self.urlStr];
      NSData *data = [NSData dataWithContentsOfURL:url];

      if (self.isCancelled) return;

      if (data != nil) {
      [data writeToFile:self.urlStr.appendCachePath atomically:YES];
      }

      if (self.isCancelled) return;

      if (self.completion && data != nil) {

      [[NSOperationQueue mainQueue] addOperationWithBlock:^{

      self.completion([UIImage imageWithData:data]);
      }];
      }
      }
      }
    • WebImageManager.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      //  负责所有网络图像的下载操作以及缓存管理!
      @interface WebImageManager : NSObject

      /// 全局单例访问入口
      + (instancetype)sharedManager;

      /// 下载网络图像
      - (void)downloadImage:(NSString *)urlString completion:(void (^) (UIImage *image))completion;

      /// 取消 urlString 对应的下载操作
      - (void)cancelDownload:(NSString *)urlString;

      @end
    • WebImageManager.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      /// 下载队列
      @property (nonatomic, strong) NSOperationQueue *downloadQueue;

      /// 下载操作缓冲池
      @property (nonatomic, strong) NSMutableDictionary *downloadQueueCache;

      /// 图片缓冲池
      @property (nonatomic, strong) NSMutableDictionary *imageCache;

      // 下载管理器

      // 实例化下载管理器
      + (instancetype)sharedManager {

      static id instance;

      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
      instance = [[self alloc] init];
      });
      return instance;
      }

      // 下载操作

      - (void)downloadImage:(NSString *)urlString completion:(void (^)(UIImage *))completion {

      // 判断缓存中是否存在图像
      if ([self checkCacheWithURLString:urlString]) {

      if (completion != nil) {

      // 直接回调,传递给调用方图像
      completion(self.imageCache[urlString]);
      }

      return;
      }

      // 判断缓冲池中是否存在下载操作
      if (self.downloadQueueCache[urlString] != nil) {

      return;
      }

      WebImageOperation *downloadOperation = [WebImageOperation webImageOperationWithURLString:urlString
      completion:^(UIImage *image) {

      // 下载完成从操作缓冲池中移除操作
      [self.downloadQueueCache removeObjectForKey:urlString];

      // 下载完成添加到图片缓冲池中
      [self.imageCache setObject:image forKey:urlString];

      if (completion != nil) {
      completion(image);
      }
      }];

      // 将操作添加到缓冲池
      [self.downloadQueueCache setObject:downloadOperation forKey:urlString];

      // 将操作添加到队列
      [self.downloadQueue addOperation:downloadOperation];
      }

      // 取消 urlString 对应的下载操作
      - (void)cancelDownload:(NSString *)urlString {

      // 从缓冲池拿到下载操作
      WebImageOperation *downloadOperation = self.downloadQueueCache[urlString];

      if (downloadOperation != nil) {

      // 取消操作
      [downloadOperation cancel];

      // 从缓冲池中删除操作
      [self.downloadQueueCache removeObjectForKey:urlString];
      }
      }

      // 判断缓存中是否存在图像
      - (BOOL)checkCacheWithURLString:(NSString *)urlString {

      // 判断图片缓冲池中是否存在图像
      if (self.imageCache[urlString] != nil) {
      return YES;
      }

      UIImage *image = [UIImage imageWithContentsOfFile:[urlString appendCachePath]];

      // 判断沙盒中是否存在图像
      if (image != nil) {

      [self.imageCache setObject:image forKey:urlString];

      return YES;
      }

      return NO;
      }

      // 懒加载

      - (NSOperationQueue *)downloadQueue {
      if (_downloadQueue == nil) {
      _downloadQueue = [[NSOperationQueue alloc] init];
      }
      return _downloadQueue;
      }

      - (NSMutableDictionary *)downloadQueueCache {
      if (_downloadQueueCache == nil) {
      _downloadQueueCache = [[NSMutableDictionary alloc] init];
      }
      return _downloadQueueCache;
      }

      - (NSMutableDictionary *)imageCache {
      if (_imageCache == nil) {
      _imageCache = [[NSMutableDictionary alloc] init];
      }
      return _imageCache;
      }
    • UIImageView+WebImageView.h

      1
      2
      3
      4
      5
      6
      @interface UIImageView (WebImageView)

      /// 设置 Web 图像 URL,自动加载图像
      - (void)setWebImageWithURL:(NSString *)urlString;

      @end
    • UIImageView+WebImageView.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      #import <objc/runtime.h>

      // 下载图片的 url
      @property (nonatomic, copy) NSString *urlStr;

      - (void)setWebImageWithURL:(NSString *)urlString {

      // 屏蔽快速滑动重复添加下载
      if ([self.urlStr isEqualToString:urlString]) {

      return;
      }

      // 暂停之前的操作
      if (self.urlStr != nil && ![self.urlStr isEqualToString:urlString]) {

      [[WebImageManager sharedManager] cancelDownload:self.urlStr];

      // 如果 ImageView 之前有图像-清空图像
      self.image = nil;
      }

      // 记录新的 url
      self.urlStr = urlString;

      __weak typeof(self) weakSelf = self;

      // 下载网络图片
      [[WebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
      weakSelf.image = image;
      }];
      }

      // 向分类添加属性

      // 运行时的关联对象,动态添加属性
      const void *URLStrKey = "URLStrKey";

      - (void)setUrlStr:(NSString *)urlString {
      objc_setAssociatedObject(self, URLStrKey, urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
      }

      - (NSString *)urlStr {
      return objc_getAssociatedObject(self, URLStrKey);
      }
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      /// 表格数据源
      @property (nonatomic, strong) NSArray *dataSourceArray;

      // 懒加载

      - (NSArray *)dataSourceArray {
      if (_dataSourceArray == nil) {
      _dataSourceArray = [AppInfoModel loadPList];
      }
      return _dataSourceArray;
      }

      // 表格视图数据源方法

      - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return self.dataSourceArray.count;
      }

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

      AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      cell.nameLabel.text = dataModel.name;
      cell.downloadLabel.text = dataModel.download;

      [cell.iconImageView setWebImageWithURL:dataModel.icon];

      return cell;
      }
  • Swift

    • AppInfoModel.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      class AppInfoModel: NSObject

      var name: String!
      var icon: String!
      var download: String!

      class func loadPList() -> [AnyObject] {
      let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!)

      var plist: [AnyObject] = Array()
      array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer<ObjCBool>) in

      let model: AnyObject = self.init()

      model.setValuesForKeysWithDictionary(obj as! [String : AnyObject])

      plist.append(model)
      }
      return plist
      }

      class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject {
      let obj: AnyObject = self.init()

      obj.setValuesForKeysWithDictionary(dict)

      return obj
      }

      required override init() {
      super.init()
      }
    • AppInfoCell.swift

      1
      2
      3
      @IBOutlet weak var iconView: UIImageView!
      @IBOutlet weak var nameLabel: UILabel!
      @IBOutlet weak var downLabel: UILabel!
    • String+BundlePath.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      ///  拼接缓存目录
      public func appendCachePath() -> String? {
      let dir: String? = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true).last
      if (dir != nil) {
      return dir! + "/" + (self as NSString).lastPathComponent
      } else {
      return nil
      }
      }
    • WebImageOperation.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      class WebImageOperation: NSOperation

      /// 下载图片的 URL
      var urlStr: String!

      /// 下载完成的回调
      var completion:((image:UIImage) -> Void)!

      class func webImageOperationWithURLString(urlString:String, completion:((image:UIImage) -> Void)) -> WebImageOperation {

      let imageOperation:WebImageOperation = WebImageOperation()

      imageOperation.urlStr = urlString
      imageOperation.completion = completion

      return imageOperation
      }

      // 操作加入队列后会自动执行该方法
      override func main() {

      if self.cancelled == true {
      return
      }

      let url: NSURL = NSURL(string: self.urlStr)!
      let data: NSData? = NSData(contentsOfURL: url)

      if self.cancelled == true {
      return
      }

      if data != nil {

      data?.writeToFile(self.urlStr.appendCachePath()!, atomically: true)
      }

      if self.cancelled == true {
      return
      }

      if (self.completion != nil) && (data != nil) {

      NSOperationQueue.mainQueue().addOperationWithBlock({

      self.completion(image: UIImage(data: data!)!)
      })
      }
      }
    • WebImageManager.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      // 负责所有网络图像的下载操作以及缓存管理!
      class WebImageManager: NSObject

      // 下载队列
      lazy var downloadQueue:NSOperationQueue = {

      var tmp: NSOperationQueue = NSOperationQueue()
      return tmp
      }()

      // 下载缓冲池
      lazy var downloadQueueCache:[String:WebImageOperation] = {

      var tmp: [String:WebImageOperation] = Dictionary()
      return tmp
      }()

      // 图片缓冲池
      lazy var imageCache: [String:UIImage] = {

      var tmp: [String:UIImage] = Dictionary()
      return tmp
      }()

      // 下载管理器

      static let sharedManager = WebImageManager()
      private override init() {}

      // 下载操作

      func downloadImage(urlString:String, completion:((image:UIImage) -> Void)?) {

      // 判断缓存中是否存在图像
      if self.checkCacheWithURLString(urlString) == true {

      if completion != nil {

      // 直接回调,传递给调用方图像
      completion!(image: self.imageCache[urlString]!)
      }

      return
      }

      // 判断缓冲池中是否存在下载操作
      if self.downloadQueueCache[urlString] != nil {

      print("玩命下载中...稍安勿躁!")

      return
      }

      let downloadOperation:WebImageOperation = WebImageOperation.webImageOperationWithURLString(urlString) { (image) in

      // 下载完成从操作缓冲池中移除操作
      self.downloadQueueCache.removeValueForKey(urlString)

      // 下载完成添加到图片缓冲池中
      self.imageCache[urlString] = image

      if (completion != nil) {
      completion!(image: image);
      }
      }

      // 将操作添加到缓冲池
      self.downloadQueueCache[urlString] = downloadOperation

      // 将操作添加到队列
      self.downloadQueue.addOperation(downloadOperation)
      }

      // 取消 urlString 对应的下载操作
      func cancelDownload(urlString:String) {

      // 从缓冲池拿到下载操作
      let downloadOperation:WebImageOperation? = self.downloadQueueCache[urlString]

      if downloadOperation != nil {

      print("取消下载操作")

      // 取消操作
      downloadOperation!.cancel()

      // 从缓冲池中删除操作
      self.downloadQueueCache.removeValueForKey(urlString)
      }
      }

      // 判断缓存中是否存在图像
      func checkCacheWithURLString(urlString:String) -> Bool {

      // 判断图片缓冲池中是否存在图像
      if self.imageCache[urlString] != nil {

      print("从内存中加载...")

      return true
      }

      let image:UIImage? = UIImage(contentsOfFile: urlString.appendCachePath()!)

      // 判断沙盒中是否存在图像
      if image != nil {

      print("从沙盒中加载...")

      self.imageCache[urlString] = image

      return true
      }

      return false
      }
    • UIImageView+WebImageView.h

      1
      2
      3
      4
      5
      6
      @interface UIImageView (WebImageView)

      /// 设置 Web 图像 URL,自动加载图像
      - (void)setWebImageWithURL:(NSString *)urlString;

      @end
    • UIImageView+WebImageView.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      #import <objc/runtime.h>
      #import "SwiftImageCache-Swift.h"

      // 下载图片的 url
      @property (nonatomic, copy) NSString *urlStr;

      - (void)setWebImageWithURL:(NSString *)urlString {

      // 屏蔽快速滑动重复添加下载
      if ([self.urlStr isEqualToString:urlString]) {

      return;
      }

      // 暂停之前的操作
      if (self.urlStr != nil && ![self.urlStr isEqualToString:urlString]) {

      [[WebImageManager sharedManager] cancelDownload:self.urlStr];

      // 如果 ImageView 之前有图像-清空图像
      self.image = nil;
      }

      // 记录新的 url
      self.urlStr = urlString;

      __weak typeof(self) weakSelf = self;

      // 下载网络图片
      [[WebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
      weakSelf.image = image;
      }];
      }

      // 向分类添加属性

      // 运行时的关联对象,动态添加属性
      const void *URLStrKey = "URLStrKey";

      - (void)setUrlStr:(NSString *)urlString {
      objc_setAssociatedObject(self, URLStrKey, urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
      }

      - (NSString *)urlStr {
      return objc_getAssociatedObject(self, URLStrKey);
      }
    • SwiftImageCache-Bridging-Header.h

      1
      #import "UIImageView+WebImageView.h"
    • ViewController.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      // 懒加载

      lazy var dataSourceArray:[AnyObject] = {
      var tmp: [AnyObject] = AppInfoModel.loadPList()
      return tmp
      }()

      // 表格视图数据源方法

      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return self.dataSourceArray.count
      }

      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

      let cell: AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      cell.nameLabel.text = dataModel.name
      cell.downLabel.text = dataModel.download

      cell.iconView.setWebImageWithURL(dataModel.icon)

      return cell
      }

5、SDWebImage 缓存方式

  • Github 网址:SDWebImage

  • SDWebImage 使用 ARC

  • Objective-C

    1
    2
    3
    4
    5
    // 添加第三方库文件
    SDWebImage

    // 包含头文件
    #import "UIImageView+WebCache.h"
    • AppInfoModel.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @interface AppInfoModel : NSObject

      /// 标题名称
      @property (nonatomic, strong) NSString *name;

      /// 下载数量
      @property (nonatomic, strong) NSString *download;

      /// 图片地址
      @property (nonatomic, strong) NSString *icon;

      /// 从 Plist 加载 AppInfo
      + (NSArray *)loadPList;

      @end
    • AppInfoModel.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      + (NSArray *)loadPList {

      NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]];

      NSMutableArray *plist = [NSMutableArray arrayWithCapacity:array.count];
      [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

      id model = [[self alloc] init];
      [model setValuesForKeysWithDictionary:obj];

      [plist addObject:model];
      }];

      return plist;
      }
    • AppInfoCell.h

      1
      2
      3
      4
      5
      6
      7
      @interface AppInfoCell : UITableViewCell

      @property (nonatomic, weak) IBOutlet UILabel *nameLabel;
      @property (nonatomic, weak) IBOutlet UILabel *downloadLabel;
      @property (nonatomic, weak) IBOutlet UIImageView *iconImageView;

      @end
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      /// 表格数据源
      @property (nonatomic, strong) NSArray *dataSourceArray;

      // 懒加载

      - (NSArray *)dataSourceArray {
      if (_dataSourceArray == nil) {
      _dataSourceArray = [AppInfoModel loadPList];
      }
      return _dataSourceArray;
      }

      // 表格视图数据源方法

      - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return self.dataSourceArray.count;
      }

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

      AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];

      AppInfoModel *dataModel = self.dataSourceArray[indexPath.row];

      cell.nameLabel.text = dataModel.name;
      cell.downloadLabel.text = dataModel.download;

      [cell.iconImageView sd_setImageWithURL:[NSURL URLWithString:dataModel.icon]];

      return cell;
      }
  • Swift

    1
    2
    3
    4
    5
    6
    7
    8
    // 添加第三方库文件
    SDWebImage

    // 创建桥接头文件,如
    SwiftImageCache-Bridging-Header.h

    // 在桥接头文件中添加头文件
    #import "UIImageView+WebCache.h"
    • AppInfoModel.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      class AppInfoModel: NSObject	

      var name: String!
      var icon: String!
      var download: String!

      class func loadPList() -> [AnyObject] {
      let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!)

      var plist: [AnyObject] = Array()
      array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer<ObjCBool>) in

      let model: AnyObject = self.init()

      model.setValuesForKeysWithDictionary(obj as! [String : AnyObject])

      plist.append(model)
      }
      return plist
      }

      class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject {
      let obj: AnyObject = self.init()

      obj.setValuesForKeysWithDictionary(dict)

      return obj
      }

      required override init() {
      super.init()
      }
    • AppInfoCell.swift

      1
      2
      3
      4
      5
      class AppInfoCell: UITableViewCell

      @IBOutlet weak var iconView: UIImageView!
      @IBOutlet weak var nameLabel: UILabel!
      @IBOutlet weak var downLabel: UILabel!
    • ViewController.swift

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      // 懒加载

      lazy var dataSourceArray:[AnyObject] = {
      var tmp: [AnyObject] = AppInfoModel.loadPList()
      return tmp
      }()

      // 表格视图数据源方法

      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return self.dataSourceArray.count
      }

      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

      let cell: AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell

      let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel

      cell.nameLabel.text = dataModel.name
      cell.downLabel.text = dataModel.download

      // 设置图片
      cell.iconView.sd_setImageWithURL(NSURL(string: dataModel.icon))

      return cell
      }
文章目录
  1. 1. 1、ImageCache
  2. 2. 2、自定义内存缓存方式
  3. 3. 3、自定义沙盒缓存方式
  4. 4. 4、仿 SDWebImage 缓存方式
  5. 5. 5、SDWebImage 缓存方式
隐藏目录