【问题标题】:RootViewController - tableView:cellForRowAtIndexPath - Load image from assetsLibraryRootViewController - tableView:cellForRowAtIndexPath - 从 assetsLibrary 加载图像
【发布时间】:2011-09-29 16:52:34
【问题描述】:

StackOverflow 的朋友和同事程序员,

我的 RootViewController(视图上的花表视图)应该显示单元格的标题、副标题和图像缩略图(从相机胶卷加载)。我猜是一个非常基本的表格。

所有内容都存储在“核心数据”中,但图像存储为相机胶卷的 imagePaths。示例:flower.imagePath = assets-library://asset/asset.JPG?id=1000000002&ext

使用底部的代码,一切都应该顺利运行,但事实并非如此。启动应用程序时,会显示标题和副标题,但不显示图像。当我按下一个显示详细视图的单元格并再次弹出到主视图时,将显示该特定单元格的图像。

当我按下“显示全部”时,工具栏上的一个按钮会执行以下代码

NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
[fetchRequest setPredicate:nil];

NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}
[self.flowerTableView reloadData];

然后重新加载表格,所有美丽的花朵现在都显示出来了。

为什么第一次没有展示鲜花?这是缓存问题吗?

调试此代码时,在启动应用程序时加载表后记录字符串:“此调试字符串在此功能完成后记录”,而不是在按“显示全部”后记录 这意味着所有图像均已成功从相机胶卷加载,但在单元格显示后附加到单元格,因此未显示。

按“显示全部”时,会按预期打印同一行

希望有人能告诉我这里发生了什么,甚至更好的是,在我的代码中进行哪些更改以使其正常工作。我现在卡住了……

感谢您帮助我! 埃德温

:::代码:::

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath
{

    Flower *flower = [fetchedResultsController_ objectAtIndexPath:indexPath];

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...

    // Display the image if one is defined
    if (flower.imagePath && ![flower.imagePath isEqualToString:@""])
    {
        // Should hold image after executing the resultBlock
       __block UIImage *image = nil;

        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *asset)
        {
            NSLog(@"This debug string was logged after this function was done");
            image = [[UIImage imageWithCGImage:[asset thumbnail]] retain];
        };

        ALAssetsLibraryAccessFailureBlock failureBlock  = ^(NSError *error)
        {
            NSLog(@"Unresolved error: %@, %@", error, [error localizedDescription]);
        };

        [assetsLibrary_ assetForURL:[NSURL URLWithString:flower.imagePath] 
                        resultBlock:resultBlock
                       failureBlock:failureBlock];

        [cell.imageView setImage:image];
    }

    return cell;
}

【问题讨论】:

    标签: iphone ios image objective-c-blocks alasset


    【解决方案1】:

    -[ALAssetsLibraryassetForURL:resultBlock:failureBlock] 异步运行。这意味着调用会立即在您的 tableView:cellForRowAtIndexPath: 方法中返回。在实际加载资产之前,单元格会显示在表格视图中。

    您需要做的是为结果块中的单元格设置图像。像这样的:

    if (flower.imagePath && ![flower.imagePath isEqualToString:@""])
    {
        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *asset)
        {
            NSLog(@"This debug string was logged after this function was done");
            [cell.imageView setImage:[UIImage imageWithCGImage:[asset thumbnail]]];
    
            //this line is needed to display the image when it is loaded asynchronously, otherwise image will not be shown as stated in comments
            [cell setNeedsLayout]; 
    
        };
    
        ALAssetsLibraryAccessFailureBlock failureBlock  = ^(NSError *error)
        {
            NSLog(@"Unresolved error: %@, %@", error, [error localizedDescription]);
        };
    
        [assetsLibrary_ assetForURL:[NSURL URLWithString:flower.imagePath] 
                        resultBlock:resultBlock
                       failureBlock:failureBlock];
    }
    

    【讨论】:

    • 另外,请注意资产 URL 的格式可能会因 iOS 版本而异。您将资产 URL 存储在数据库中,但不能保证当用户升级到 iOS5 时它们仍然有效。
    • 我也尝试了那行代码来完成这个任务,但由于异步执行它也失败了。图像已加载但未显示。我需要的是 table:cellForRowAtIndexPath 之后的 reloadData 但这将永远循环...... ;-)
    • 还有一件事,我听起来有点像科伦坡......如果图像的加载是异步完成的,为什么当我按下“显示全部”时,完全相同的功能是以完全相同的方式执行,但现在图像以同步方式加载。因此,当我进行一些调试时,第一个输出将是:-function start, -function end, -loading image。第二个输出是:-function start, -loading image, -function end.
    • 关键是方法可能异步运行,所以你必须假设它会。不可能知道 ALAssetsLibrary 在内部做什么以及何时调用完成块。例如,在第一次调用时,ALAssetLibrary 需要检查用户是否已授予您的应用程序访问库的权限,如果没有,可能会显示一个对话框。如果可以的话,它还可以缓存资产并同步返回。
    • 感谢您的帮助罗宾!我将添加一些代码来将图像的缩略图存储在核心数据中,这将在表格中显示。不再为表视图执行异步代码...
    【解决方案2】:

    Fellowist 朋友让我提出以下解决方案:

    而不是在 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath 中创建单元格

    创建一个 NSMutableArray,其中填充了要在表格中显示的 UITableViewCells(与您在 cellForRowAtIndexPath 方法中创建的相同) 并在 cellForRowAtIndexPath 方法中简单地返回相关的 UITableViewCell(它将是 NSMutableArray 中的一个对象)。

    这样,cellForRowAtIndexPath 方法将显示已加载并准备显示的单元格。

    【讨论】:

    • 在 cellForRowAtIndexPath 委托方法中创建单元格的要点是您可以利用 UITableView 的单元格重用和出队。这意味着即使您的表格包含数千行,您也只需要创建最少数量的单元格。
    • 感谢您的反馈和脑循环。你能给我一些关于如何实现它的代码吗?请记住,可能会使用 1000 条带图像的记录。
    • 不确定您在此回复谁,Edwin、我或 Zigglzworth,但不要这样做。 UITableView 的关键特性之一是它将重用单元格实例。如果您接受 Zigglzworth 的建议,您将绕过此功能。而是解决原来的问题。
    • @Robin :显然,您可以在向下滚动 uitableview 时将更多单元格加载到数组中,您不需要一次将 1000 个单元格添加到数组中。我已经用过很多次了,效果很好。
    • @Zigglzworth :好的,但是如果您正确使用它,您基本上是在重新实现 UITableView 已经提供的单元缓存。
    猜你喜欢
    • 2011-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2017-06-11
    • 2014-06-27
    • 2019-08-17
    相关资源
    最近更新 更多