ALAssetsLibrary似乎返回了错误的照片数量

时间:2012-07-12 09:35:54

标签: ios ipad photos alassetslibrary

当我使用ALAssetsLibrary获取本地照片时,它可以正常工作。但是在我使用“照片”应用程序删除了一些照片后,我的应用程序崩溃了。

崩溃信息是:

"Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSOrderedSet enumerateObjectsAtIndexes:options:usingBlock:]: index 14 beyond bounds [0 .. 9]'".'14'

看起来本地照片的数量仍然与befoore相同。即使在我退出应用程序并重新启动它之后,它仍然会崩溃。

本地照片访问代码:

dispatch_async(dispatch_get_main_queue(), ^
{
   @autoreleasepool 
   {
       ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
       {
           NSLog(@"error occour =%@", [myerror localizedDescription]);
       };

       ALAssetsGroupEnumerationResultsBlock groupEnumerAtion = ^(ALAsset *result, NSUInteger index, BOOL *stop)
       {
           if (result!=NULL) 
           {
               if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) 
               {
                   [self.g_imageArray addObject:result];
               }
           }
       };

       ALAssetsLibraryGroupsEnumerationResultsBlock
       libraryGroupsEnumeration = ^(ALAssetsGroup* group, BOOL* stop)
       {
           if (group == nil) 
           {
               return;
           }

           if (group!=nil) {
               [group enumerateAssetsUsingBlock:groupEnumerAtion];
           }
       [self updatephotoList];
       };

       self.library = [[ALAssetsLibrary alloc] init];
       [self.library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
                              usingBlock:libraryGroupsEnumeration 
                            failureBlock:failureblock];
   }
});

如果我用系统相机拍摄另一张照片,我的应用程序会再次确定。

7 个答案:

答案 0 :(得分:2)

这似乎是一个iOS错误,就像你说ALAssetsLibrary返回错误的照片数量所以你得到了索引越界错误。解决方法是重新加载您的照片,如下所示:

ALAssetsLibraryGroupsEnumerationResultsBlock
libraryGroupsEnumeration = ^(ALAssetsGroup* group, BOOL* stop)
{
       if (group == nil) 
       {
           return;
       }
       //Force to reload photo as numberOfAssets is broken
       NSLog(@"how many picture I have in this group: %d",[group numberOfAssets]);
       [group setAssetsFilter:[ALAssetsFilter allPhotos]];//this will cause group to reload
       NSLog(@"how many picture I have in this group: %d",[group numberOfAssets]);

       if (group!=nil) {
           [group enumerateAssetsUsingBlock:groupEnumerAtion];
       }
   [self updatephotoList];
 };

答案 1 :(得分:1)

在我的案例中注册观察员没有帮助。用户仍在崩溃,但我没有。直到今天。

我想出了解决这次崩溃的方法。最后这是Apple的照片库中的一个错误,但有一个解决方法。你所做的是,你将过滤器设置为照片,然后设置为视频,而不是将其保留为默认的“资产”。然后,您可以为每个枚举一次,并做一些技巧,以确保您获得最终的“at null”点,以执行您需要的任何更新。我目前的方法有点乱,但你明白了:

// pending is used to tell the block we're not done, even if result is NULL
BOOL pending = YES;
// resorted is just a flag I use in case there are no videos; if there are none, the block is never called at all, and thus the == NULL part never triggers
__block BOOL resorted = NO;

ALAssetsGroupEnumerationResultsBlock assetEnumerator = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
    if(result != NULL) {
        [assets addObject:result];
    } else if (! pending) {
        // ready!!
        resorted = YES;
        [self resort]; // my own method; replace with e.g. tableView reload!
    }
};

// there are two types of assets - photos and videos; we start with photo
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
NSLog(@"assets = %d", group.numberOfAssets);
[group enumerateAssetsUsingBlock:assetEnumerator];
// we then set pending to NO; even though the enumeration happens in a separate thread, it seems like pending is not caught by the above enumeration (I have 105 images in the group I am enumerating, FWIW; it may be better to set pending in the == NULL part of the enumeration though
pending = NO;
// now we switch to video and do the same thing
[group setAssetsFilter:[ALAssetsFilter allVideos]];
BriefLog(@"assets = %d", group.numberOfAssets);
[group enumerateAssetsUsingBlock:assetEnumerator];

// if there are 0 vids, the above block is not ever called so we flip to a background thread and then back (probably not necessary) and then check if resorted is set; if it isn't we call resort
if (! resorted) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (! resorted) {
            [self resort]; // my own method; replace with e.g. tableView reload!
        }
    });
});

就是这样。 NSRangeExceptions消失了。至少在我的情况下他们做到了。

答案 2 :(得分:0)

您需要注册ALAssetsLibraryChangedNotification的观察者以获取库更改。触发通知时,重新枚举AssetsLibrary的组和内容。如果您没有注册通知,您的应用程序将获得库的旧快照,枚举将失败。 另请注意,iOS 5.x下的ALAssetsLibraryChangedNotification存在错误,如此处所述:http://www.openradar.me/10484334

答案 3 :(得分:0)

我从秋朗开始回答,但这对我没用。 对我来说有用的是在开始枚举之前,使用所有过滤器组合连续调用setAssetsFilter 3次。

[group setAssetsFilter:[ALAssetsFilter allPhotos]];
[group setAssetsFilter:[ALAssetsFilter allVideos]];
[group setAssetsFilter:[ALAssetsFilter allAssets]];

答案 4 :(得分:0)

在iOS 8中,我还注意到,如果其中一些照片被删除并位于“最近删除的”状态,则numberOfAssets会返回错误数量的照片。专辑目前。

答案 5 :(得分:0)

对于那些使用所有ALAssetRepresentations填充某些NSArray并且不想过多更改代码的人,只需使用此Checker过滤您的数组 - AssetURLChecker

干杯!

答案 6 :(得分:0)

ALAssetsLibrary库在PHAssetsLibrary上进行了描述,因此请使用以下代码:

__block PHAssetCollection *collection;
    _arr_downloadedWallpaper = [[NSMutableArray alloc] init];

    // Find the album
    PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
    fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", @"Bhakti Ras"];
    collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                          subtype:PHAssetCollectionSubtypeAny
                                                          options:fetchOptions].firstObject;

    PHFetchResult *collectionResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];

    [collectionResult enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {

        //add assets to an array for later use in the uicollectionviewcell
        NSLog(@"asset is =%@",asset);


        if (asset) {
            [self.arr_downloadedWallpaper addObject:asset];
        }
    }];