实现
#import "MZTableViewController.h"
/// 模型类
@interface MZInfoModel : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *subName;
@property (nonatomic, copy) NSString *imageUrl;
+ (instancetype)modelWithDictionary:(NSDictionary *)dict;
@end
@implementation MZInfoModel
+ (instancetype)modelWithDictionary:(NSDictionary *)dict {
MZInfoModel *model = [[MZInfoModel alloc] init];
[model setValuesForKeysWithDictionary:dict];
return model;
}
// 为了防止字典里有的 key,但模型里没有对应的属性而导致 crash
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {}
@end
@interface MZTableViewController ()
@property (nonatomic, strong) NSArray *dataList; ///< 用于存放数据源
@property (nonatomic, strong) NSMutableDictionary *memoryDict; ///< 图片的内存缓存
@property (nonatomic, strong) NSOperationQueue *queue; ///< 下载图片的队列
@property (nonatomic, strong) NSMutableDictionary *operationDict; ///< 操作缓存
@end
@implementation MZTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ID = @"ReuseId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
MZInfoModel *model = self.dataList[indexPath.row];
cell.textLabel.text = model.name;
cell.detailTextLabel.text = model.subName;
// 读取内存中的图片
UIImage *image = [self.memoryDict objectForKey:model.imageUrl];
if (image) {// 内存中有图片
cell.imageView.image = image;
NSLog(@"使用了内存中的图片");
} else {// 内存中不存在对应的图片
// 先去缓存中读取
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [model.imageUrl lastPathComponent];
NSString *fullPath = [cachePath stringByAppendingPathComponent:fileName];
// 检查磁盘缓存
NSData *data = [NSData dataWithContentsOfFile:fullPath];
if (data) {// 如果磁盘中存在图片
UIImage *image = [UIImage imageWithData:data];
cell.imageView.image = image;
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
NSLog(@"读取了磁盘中的图片");
// 写入内存缓存
[self.memoryDict setValue:image forKey:model.imageUrl];
} else {// 磁盘中不存在,就去下载
// 处理下载图片耗时时间长的场景:检查图片是否在下载,如果没有,就去下载
NSBlockOperation *operation = [self.operationDict objectForKey:model.imageUrl];
if (!operation) {
// 防止图片没有下载出来时,导致图片显示错乱的问题
cell.imageView.image = nil;
operation = [NSBlockOperation blockOperationWithBlock:^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:model.imageUrl]];
// 将图片的二进制流写入磁盘
[data writeToFile:fullPath atomically:YES];
UIImage *image = [UIImage imageWithData:data];
// 如果图片不存在
if (!image) {
// 移除图片的下载操作
[self.operationDict removeObjectForKey:model.imageUrl];
return;
}
// 将图片缓存到内存
[self.memoryDict setValue:image forKey:model.imageUrl];
// 图片下载成功后,移除图片的下载操作
[self.operationDict removeObjectForKey:model.imageUrl];
// 切换到主线程刷新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
cell.imageView.image = image;
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
NSLog(@"下载图片");
}];
}];
// 添加操作到缓存
[self.operationDict setValue:operation forKey:model.imageUrl];
[self.queue addOperation:operation];
}
}
}
return cell;
}
#pragma mark - Getter
- (NSOperationQueue *)queue {
if (!_queue) {
_queue = [[NSOperationQueue alloc] init];
// 设置最大并发数
_queue.maxConcurrentOperationCount = 5;
}
return _queue;
}
- (NSMutableDictionary *)operationDict {
if (!_operationDict) {
_operationDict = [NSMutableDictionary dictionary];
}
return _operationDict;
}
- (NSArray *)dataList {
if (!_dataList) {
// 获取文件数据源
NSArray *source = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"SourceData.plist" ofType:nil]];
NSMutableArray *array = [NSMutableArray array];
[source enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) {
[array addObject:[MZInfoModel modelWithDictionary:source[idx]]];
}];
_dataList = array;
}
return _dataList;
}
@end
SourceData.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>人民重重0</string>
<key>subName</key>
<string>爱编程0</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/03/13/b2ec25f9bd4d2f01_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重1</string>
<key>subName</key>
<string>爱编程1</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/03/13/38a15ebde8697ecb_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重2</string>
<key>subName</key>
<string>爱编程2</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/03/04/b8b13c27b20c2692_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重3</string>
<key>subName</key>
<string>爱编程3</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/02/12/80cfd95fc8b42a90_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重4</string>
<key>subName</key>
<string>爱编程4</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/02/12/642e00168836ca5e_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重5</string>
<key>subName</key>
<string>爱编程5</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/23/1e8ec7195a25fb36_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重6</string>
<key>subName</key>
<string>爱编程6</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/23/ed8933509da89255_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重7</string>
<key>subName</key>
<string>爱编程7</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/12/6523d1ad55f60928_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重8</string>
<key>subName</key>
<string>爱编程8</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/08/d4e754b68ddb29f3_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重9</string>
<key>subName</key>
<string>爱编程9</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/08/cef0f09f48f9e1bd_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重10</string>
<key>subName</key>
<string>爱编程10</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2019/01/02/061f708898d04be1_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重11</string>
<key>subName</key>
<string>爱编程11</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2018/12/29/19fa17bb12716b95_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重12</string>
<key>subName</key>
<string>爱编程12</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2018/12/07/caa6c6d36f87584b_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重13</string>
<key>subName</key>
<string>爱编程13</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2018/11/09/28120072111a8b22_300x300.jpg</string>
</dict>
<dict>
<key>name</key>
<string>人民重重14</string>
<key>subName</key>
<string>爱编程14</string>
<key>imageUrl</key>
<string>https://img.tuzhaozhao.com/2018/10/31/d568ab1fa75c628d_300x300.jpg</string>
</dict>
</array>
</plist>