我正在开发一个UITableView,它非常像iOS的原生Photo应用程序:它有很多行,每行有4个图像缩略图。 (即每个UITableViewCell都有4个UIImageViews)所有缩略图都是从Core Data加载的。
我已经多次修改了我的实现,我可以看到性能改进,但仍然无法像Photo应用程序那样顺利滚动。
我需要建议如何正确缓存照片以获得最佳性能。这就是我试过的:
1。我的第一次尝试(滚动时非常滞后)
2。第二次尝试(更快,但滚动时仍然滞后)
使用NSCache缓存从CoreData加载的图像后,滚动速度明显加快,但由于在NSCache中尚不可用时仍需从CoreData加载图像,因此滚动仍会不时地生涩。
所以,必须有一个更好的方法,我可以将所有图像预加载到内存中,但由于可能有大量或多行图像,所以我根本不打算预加载图像。
我还可以在cellForRowAtIndexPath中更快地加载图像吗?
答案 0 :(得分:26)
无论数据来自何处,都要保持滚动顺畅,您需要在单独的线程上获取数据,并且只有在内存中存储数据时才更新UI。 Grand Central Despatch 是要走的路。这是一个骨架,假设你有一个self.photos
字典,其中包含对图像文件的文本引用。图像缩略图可以加载或不加载到实时字典中;可能在文件系统缓存中,也可能不在;否则从网上商店取货。它可以使用核心数据,但平滑滚动的关键是你不要等待数据来自
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Photo Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//identify the data you are after
id photo = [self.photos objectAtIndex:indexPath.row];
// Configure the cell based on photo id
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//move to an asynchronous thread to fetch your image data
UIImage* thumbnail = //get thumbnail from photo id dictionary (fastest)
if (!thumbnail) { //if it's not in the dictionary
thumbnail = //get it from the cache (slower)
// update the dictionary
if (!thumbnail) { //if it's not in the cache
thumbnail = //fetch it from the (online?) database (slowest)
// update cache and dictionary
}
}
}
if (thumbnail) {
dispatch_async(dispatch_get_main_queue(), ^{
//return to the main thread to update the UI
if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
//check that the relevant data is still required
UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];
//get the correct cell (it might have changed)
[[correctCell imageView] setImage:thumbnail];
[correctCell setNeedsLayout];
}
});
}
});
return cell;
}
如果您正在使用某种单例映像存储管理器,您可能希望管理器处理缓存/数据库访问的详细信息,这简化了此示例。
这部分
UIImage* thumbnail = //get thumbnail from photo id dictionary (fastest)
if (!thumbnail) { //if it's not in the dictionary
thumbnail = //get it from the cache (slower)
// update the dictionary
if (!thumbnail) { //if it's not in the cache
thumbnail = //fetch it from the (online?) database (slowest)
// update cache and dictionary
}
}
将替换为
之类的内容 UIImage* thumbnail = [[ImageManager singleton] getImage];
(当你返回主队列时,你不会使用完成块,因为你在GCD中有效提供了一个)
答案 1 :(得分:0)
我使用了一个名为JMImageCache的类来将图像缓存到磁盘,然后只在CoreData中存储本地URL(如果您愿意,还存储远程URL)。您还可以生成一个缩略图,同时保存到磁盘并将缩略图URL与图像URL一起存储在核心数据中,并在表格视图中使用缩略图。
答案 2 :(得分:0)
为核心数据中的图像添加NSValueTransformer的子类
代码如下:
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSData class];
}
- (id)transformedValue:(id)value {
return UIImageJPEGRepresentation(value, 0.5);
}
- (id)reverseTransformedValue:(id)value {
return [[UIImage alloc] initWithData:value];
}