无沙盒缓存
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) NSMutableDictionary *operations;
14
15 /**
16 * 全局队列
17 */
18 @property (nonatomic, strong) NSOperationQueue *queue;
19
20 /**
21 * 存储app的图标的字典
22 */
23 @property (nonatomic, strong) NSMutableDictionary *images;
24 @end
25
26 @implementation HMAppViewController
27
28 #pragma mark - 懒加载
29 - (NSArray *)apps
30 {
31 if(!_apps)
32 {
33 _apps = [HMApp apps];
34 }
35 return _apps;
36 }
37
38 - (NSMutableDictionary *)operations
39 {
40 if(!_operations)
41 {
42 _operations = [NSMutableDictionary dictionary];
43 }
44 return _operations;
45 }
46
47 - (NSOperationQueue *)queue
48 {
49 if(!_queue)
50 {
51 _queue = [[NSOperationQueue alloc] init];
52 }
53 return _queue;
54 }
55
56 - (NSMutableDictionary *)images
57 {
58 if(!_images)
59 {
60 _images = [NSMutableDictionary dictionary];
61 }
62 return _images;
63 }
64
65 - (void)viewDidLoad
66 {
67 [super viewDidLoad];
68
69 }
70
71 // 默认是一组
72 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
73 {
74 return 1;
75 }
76
77 // 每一section有多少行
78 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
79 {
80 return self.apps.count;
81 }
82
83 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
84 {
85 static NSString *ID = @"app";
86 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
87 if(!cell)
88 {
89 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
90 }
91 HMApp *app = self.apps[indexPath.row];
92 cell.textLabel.text = app.name;
93 cell.detailTextLabel.text = app.download;
94
95 // 先从images缓存中取出图片url对应的UIImage
96 // 取出url对应的图片
97 UIImage *storageImage = self.images[app.icon];
98
99 if(storageImage) // 说明图片已下载成功过(成功缓存)
100 {
101 cell.imageView.image = storageImage;
102 }
103 else
104 {
105 // 要么显示已下载好的图片,要么显示占位图片,防止cell的循环利用时显示其它的图片
106 // 占位图,确保image有尺寸,更新时可以显示最新的图片
107 cell.imageView.image = [UIImage imageNamed:@"placeholder"];
108
109 // 取出当前图片url对应的下载操作(operation对象)
110 NSBlockOperation *operation = self.operations[app.icon];
111 if(!operation)
112 {
113 operation = [NSBlockOperation blockOperationWithBlock:^{
114 [NSThread sleepForTimeInterval:2];
115
116 // 创建操作,下载app图标,下载图片是耗时的操作
117 NSURL *url = [NSURL URLWithString:app.icon];
118 NSData *data = [NSData dataWithContentsOfURL:url]; // 下载图片
119 UIImage *image = [UIImage imageWithData:data]; // data->image
120
121 // 回到主线程刷新UI
122 [[NSOperationQueue mainQueue] addOperationWithBlock:^{
123 // 设置cell图片(在子线程中的cell有可能给循环利用了,这里设置数据不合理)
124 // cell.imageView.image = image;
125
126 // 字典不能存放nil(空)的
127 if(image)
128 {
129 self.images[app.icon] = image;
130 }
131
132 // 从字典中移除下载操作
133 [self.operations removeObjectForKey:app.icon];
134
135 // 刷新表格(刷新cell所在的行)
136 // 这里会调用(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
137 [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
138 }];
139 }];
140
141 // 添加操作到队列中
142 [self.queue addOperation:operation];
143
144 // 添加到字典中(这句代码为了解决重复下载)
145 self.operations[app.icon] = operation;
146 }
147 }
148
149 return cell;
150 }
151
152 @end