ALAssetsLibrary - 收到ALAssetsLibraryChangedNotification后崩溃

10

我的应用程序的一部分有一个照片浏览器,有点类似于苹果的照片应用程序,有一个初始视图控制器来浏览照片缩略图和一个详细视图,当您点击照片时显示它。

我使用ALAssetsLibrary访问照片,并向我的详细视图控制器传递ALAsset URL数组,以便您可以从一个照片滑动到另一个照片。

一切都很好,直到我在滑动照片时(在详细视图控制器中),收到了ALAssetsLibraryChangedNotification,这经常导致崩溃:

NOTIFICATION: the asset library changed // 我自己的NSLog,用于当通知发生时

loading assets... // 我自己的NSLog,用于当我开始在缩略图浏览器中重新加载资源时

Assertion failed: (size == bytesRead), function - [ALAssetRepresentation _imageData],file / SourceCache / AssetsLibrary / MobileSlideShow-1373.58.1 / Sources / ALAssetRepresentation.m, line 224.

它崩溃的具体代码行是在调用[currentRep metadata]时引起的,如下所示:

- (void)someMethod {
        NSURL *assetURL = [self.assetURLsArray objectAtIndex:index];
        ALAsset *currentAsset;

        [self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {

            [self performSelectorInBackground:@selector(configureDetailViewForAsset:) withObject:asset];

            } failureBlock:^(NSError *error) {
                    NSLog(@"failed to retrieve asset: %@", error);
        }];
}

- (void)configureDetailViewForAsset:(ALAsset *)currentAsset {
    ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation];

    if (currentAsset != nil) {
        // do some stuff
    }
    else {
        NSLog(@"ERROR: currentAsset is nil");
    }

    NSDictionary *metaDictionary;
    if (currentRep != nil) {
        metaDictionary = [currentRep metadata];

        // do some other stuff
    }
    else {
        NSLog(@"ERROR: currentRep is nil");
    }
}

我知道一旦接收到通知,它将使对 ALAsset 和 ALAssetRepresentation 对象的任何引用无效... 但是如果在尝试访问某些东西时它使其无效,我该如何处理?

我已经尝试在接收通知时设置 BOOL,完全中止并防止调用 [currentRep metadata],但即使如此,有时仍然无法捕获它:

if (self.receivedLibraryChangeNotification) {
    NSLog(@"received library change notification, need to abort");
}
else {
    metaDictionary = [currentRep metadata];
}

有什么我可以做的吗?这时我几乎要放弃使用ALAssetsLibrary框架了。

(请注意,苹果开发者论坛上还有一个未解决的线程描述了同样的问题:https://devforums.apple.com/message/604430

1个回答

6

看起来问题就在这里:

[self.assetsLibrary assetForURL:nextURL 

    resultBlock:^(ALAsset *asset) {
        // You should do some stuff with asset at this scope
        ALAssetRepresentation *currentRep = [asset defaultRepresentation];
        // Assume we have a property for that
        self.assetRepresentationMetadata = [currentRep metadata];
        ...
        // assume we have a method for that
        [self updateAssetDetailsView];
    } 

    failureBlock:^(NSError *error) {
        NSLog(@"failed to retrieve asset: %@", error);
    }];

一旦您获得了用户资产,最好通过向详细信息控制器子视图提供必要的数据或缓存以供以后使用来复制资产信息。这可以帮助避免ALAsset失效问题。当发送通知ALAssetsLibraryChangedNotification时,您可能需要放弃详细信息控制器并从头查询库内容。


1
我需要做更多的测试...但这可能有所帮助。上面的代码中没有显示(因为我想在这里简化它),但是[currentRep metadata]是在后台线程中调用的。我按照您的建议将其更改为在“assetForURL”resultBlock内检索元数据字典,该方法恰好在主线程上运行。到目前为止它还没有崩溃...也许ALAssetRepresentation的-metadata方法不是线程安全的? - Jim Rhoades
这里最重要的是使用 assetForURL 获取媒体需要时间。因此,在完成块之外,您不能确定是否已下载媒体... - voromax
我更新了我的问题,以准确地展示我如何在后台线程中调用“metadata”方法。根据您的答案,我已经更改了它,以便首先检索元数据字典,然后将其和资产一起传递给我的configureDetailView方法。再次强调,我需要进行更多测试,但目前为止还不错... - Jim Rhoades

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接