当coredata中的图像加载时,UITableView滞后

时间:2016-02-02 07:37:25

标签: ios objective-c uitableview core-data

我正在使用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。

enter image description here

这里的问题只是第一次加载。向下滚动时有些代码很熟悉。我试图用我自己解决它,但现在没有运气。我已经在我们的应用程序中阅读了GCD的重要内容。 请帮助我了解更多相关信息。

更新 图像来自我拍摄的相机。我想我需要调整它。

5 个答案:

答案 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)

如果您要在数据库中存储照片,视频或音频(因此,任何可能的大文件),强烈建议您使用对它们的引用并使用文件系统来管理内容,如果您计划有数百个,可能有数千条记录或更多。

注意:不要忘记异步加载文件。

  

要记住的东西:当您获取数据时,所有内容都需要内存...

...

尝试此解决方法:

  • 打开您的数据模型
  • 选择存储属性&#34; image&#34;
  • 的实体
  • 选择存储图像的属性
  • 然后在右侧菜单&#34;数据模型检查器&#34;,
  • 选择:
    • &#34;存储在外部记录文件&#34;

这将解决问题:)