我正在使用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的重要内容。 请帮助我了解更多相关信息。
更新 图像来自我拍摄的相机。我想我需要调整它。
答案 0 :(得分:2)
为什么在setImage之后setNeedsLayout?我觉得没必要。
答案 1 :(得分:1)
如果您只有50个条目,则可以将它们全部加载 - 在后台队列中 - 并使用图像填充self.devices。您可以在viewDidLoad中或在需要刷新时启动该填充
在cellForRowAtIndexPath()中,您需要检查数据是否已填充 - 第一次通过它可能不是表格的顶部 - 并显示等待'图像或消息
在数据加载中,您应该每10条记录左右调用一次reloadData(),最后一次调用reloadData()以确保在数据可用时更新表视图。
使用这种方法,您不会看到加载表格中前几个条目所需的时间,并且性能对用户来说是好的
答案 2 :(得分:1)
通过线程化图像的创建,无法保证图像以比UITableView
滚动更快的速度返回到单元格。
您的单元格被重复使用,因此我不确定您是否需要此代码
if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
//check that the relevant data is still required
UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];
这可能会导致问题,因为如果某个单元格部分或部分在屏幕上,您将获得一个对用户或部分可见的单元格不可见的单元格。
你的问题是第一次加载。操作系统在您使用setImage
时缓存图像,以便在第一次加载后没有延迟,因此很多缓存代码都没有效果,因为第一次设置图像需要初始化对象,然后操作系统缓存它。
你的图像也很大,除非你在iPad上需要全屏,否则我会缩小尺寸。
答案 3 :(得分:1)
我建议将图像存储在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]];
}
答案 4 :(得分:1)
如果您要在数据库中存储照片,视频或音频(因此,任何可能的大文件),强烈建议您使用对它们的引用并使用文件系统来管理内容,如果您计划有数百个,可能有数千条记录或更多。
注意:不要忘记异步加载文件。
要记住的东西:当您获取数据时,所有内容都需要内存...
...
尝试此解决方法:
这将解决问题:)