ALAssetsLibrary seems to return wrong number of my photos

前端 未结 7 1076
梦毁少年i
梦毁少年i 2020-12-19 10:44

When I use ALAssetsLibrary to get local photos it works fine. But after I delete some photos with the \'Photos\' application my app crashes.

Crash info is:

7条回答
  •  梦毁少年i
    2020-12-19 11:35

    Registering an observer did not help in my case. Users were still crashing, but I didn't. Until today.

    I figured out the way to solve this crash. It's a bug in Apple's photo library in the end, but there's a workaround. What you do is, you set the filter to photo, and then to video, instead of leaving it at the default 'assets'. You then enumerate it once for each, and do some trickery to ensure you get that final 'at null' point for doing whatever updates you need. My current approach is a bit messy but you get the idea:

    // 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!
            }
        });
    });
    

    That's it. The NSRangeExceptions go away. At least in my case they did.

提交回复
热议问题