在 coredata 中加载图像时 UITableView 滞后
Posted
技术标签:
【中文标题】在 coredata 中加载图像时 UITableView 滞后【英文标题】:UITableView lag when image load in coredata 【发布时间】:2016-02-02 07:37:25 【问题描述】:我正在使用coredata
。我在coredata
中成功添加了图像,但是当我想显示列表时出现问题。当我向下滚动UITableView
时,我遇到了这个滞后问题。我读了这篇文章Loading image from CoreData at cellForRowAtIndexPath slows down scrolling。我仍然有延迟,现在我正在尝试使用LazyLoadImage
,但问题是,他们没有使用viewdidload()
。我不知道这个LazyLoadImage
。我想详细了解 Grand Central Dispatch 以及它的工作原理。
这是我的代码。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *simpleTableIdentifier = @"imageCell";
NSManagedObject *coreData = [self.devices objectAtIndex:indexPath.row];
ImageCell *cell = (ImageCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
cell = [[ImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
UIImage *imagex = [cache objectForKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
UIImage * rowImage = [UIImage imageWithData:[coreData valueForKey:@"image"]];
UIImageView * myImage = [[UIImageView alloc] initWithImage:rowImage];
myImage.contentMode = UIViewContentModeScaleAspectFill;
myImage.frame = CGRectMake(0, 0, 79, 56);
cell.name.text = [coreData valueForKey:@"name"];
if (imagex == nil)
[cache setObject:myImage.image forKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
imagex = [cache objectForKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
if(imagex)
dispatch_async(dispatch_get_main_queue(), ^
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:imagex];
[correctCell setNeedsLayout];
);
);
return cell;
如果我将列表放入控制器中,性能是否重要?我这里没有使用 xib。
这里的问题只是第一次加载。当它向下滚动时。有些代码很熟悉。我正在尝试自己解决它,但现在没有运气。我已经在我们的应用程序中阅读了 GCD 的重要性。 请帮助我了解更多相关信息。
更新 这些图像来自我拍摄的相机。我想我需要调整它的大小。
【问题讨论】:
self.devices
是您加载 tableView 的数组吗?
@noobsmcgoobs 是的。那是持有 coredata 数据列表的人。
您的数据集有多大?具体来说 - 它是否如此之大以至于您实际上只需要在需要时才检索数据,还是可以将其保存在内存中?
还有一个问题,您使用的是自定义UIImageView
而不是默认contentView
的imageView
属性?
对不起,我没有得到数据集的平均值。在哪里可以看到该数据集?
【参考方案1】:
为什么你在 setImage 之后 setNeedsLayout ?我觉得没必要。
【讨论】:
我只是将它复制到其他帖子。我会删除它 还是一样。我在第一次加载时遇到了延迟【参考方案2】:如果您只有 50 个条目,您可以将它们全部加载 - 在后台队列中 - 并使用图像填充 self.devices。您可以在 viewDidLoad 中或在需要刷新时启动该填充
在 cellForRowAtIndexPath() 中,您需要检查数据是否已填充 - 第一次通过它可能不是表格顶部 - 并显示“等待”图像或消息
在您的数据加载过程中,您应该每 10 条左右的记录调用一次 reloadData(),并在最后一次以确保在数据可用时更新表视图。
使用这种方法,您不会看到加载时间超过表中的前几个条目,并且性能对用户来说看起来不错
【讨论】:
这里的问题是我向下滚动时的第一次加载。我会尝试你的建议 顺便说一句。图像尺寸非常大。图片大小有关系吗? 取决于多大!如果您可以一次加载所有 50 张图像,那么您将在 tableview 中获得更快的移动速度。如果 50 张图片太大以至于加载它们都会导致设备崩溃,那么性能不会那么好:-) 如果它们真的很大,如何在表格中加载预览图像,并在选择时仅加载全尺寸。加载时会有延迟,但除非您计划对表中的每一行执行操作,否则性能影响会降低。 我认为图像的大小是 1905 x1876。该图像来自我拍摄的相机。我会在这里尝试你的建议【参考方案3】:通过线程创建图像,不能保证图像返回到单元格的速度比UITableView
滚动快。
您的单元格被重复使用,所以我不确定您是否需要此代码
if ([[tableView indexPathsForVisibleRows] containsObject:indexPath])
//check that the relevant data is still required
UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];
这可能会导致问题,因为如果单元格部分或部分显示在屏幕上,您将返回一个用户不可见或部分可见的单元格。
您的问题是第一次加载。当您使用setImage
时,操作系统会缓存图像,以便在第一次加载后没有延迟,因此很多缓存代码都无效,因为图像的第一次设置需要初始化对象,然后操作系统缓存它。
您的图像也很大,除非您需要在 iPad 上全屏显示,否则我会缩小尺寸。
【讨论】:
是的,图像非常大。我仍然在这里学习以减少图像。我会更新你。谢谢【参考方案4】:我建议将图像存储在 Mobile 目录中而不是核心数据中,因为核心数据在其中存储图像效率不高。
您可以将图像存储在示例代码中 1. 将所有图像存储在名为 imageArray 的数组中
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat: @"/%@",self.projectName ]];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error];
for (int i=0; i< self.imageArray.count; i++)
NSString *savedImagePath = [dataPath stringByAppendingPathComponent:[NSString stringWithFormat: @"%i.png",i ]];
UIImage *image = [self.imageArray objectAtIndex:i];
NSData *imageData = UIImagePNGRepresentation(image);
if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] removeItemAtPath:savedImagePath error:&error];
[imageData writeToFile:savedImagePath atomically:NO];
//
3。然后您可以将图像的地址存储在核心数据中,并使用
从目录中轻松检索 static NSString *simpleTableIdentifier = @"imageCell";
NSManagedObject *coreData = [self.devices objectAtIndex:indexPath.row];
ImageCell *cell = (ImageCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
cell = [[ImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
UIImage *imagex = [cache objectForKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat: @"/%@",self.projectName ]];
NSString * imgPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat: @"/image%@",indexPath.row]];
NSData *imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imgPath]];
UIImage * rowImage = [[UIImage alloc] initWithData:imgData];
UIImageView * myImage = [[UIImageView alloc] initWithImage:rowImage];
myImage.contentMode = UIViewContentModeScaleAspectFill;
myImage.frame = CGRectMake(0, 0, 79, 56);
cell.name.text = [coreData valueForKey:@"name"];
if (imagex == nil)
[cache setObject:myImage.image forKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
imagex = [cache objectForKey:[NSNumber numberWithUnsignedInteger:indexPath.row]];
【讨论】:
感谢这个人。我会研究这个。这里的另一个知识。我会更新你。再次感谢。【参考方案5】:如果您在数据库中存储照片、视频或音频(因此,任何可能的大文件),强烈建议使用对它们的引用并使用文件系统来管理内容,特别是如果您计划拥有数百个,可能有数千条记录或更多。
注意:不要忘记异步加载文件。
要记住的事情:当您获取数据时,一切都会占用内存......
..
试试这个解决方法:
打开您的数据模型 选择存储属性“image”的实体 选择存储图片的属性, 然后在右侧菜单“Data Model Inspector”中, 选择: “存储在外部记录文件中”这样就行了:)
【讨论】:
以上是关于在 coredata 中加载图像时 UITableView 滞后的主要内容,如果未能解决你的问题,请参考以下文章