ALAssetsLibrary semble returnner le mauvais numéro de mes photos

Lorsque j'utilise ALAssetsLibrary pour get des photos locales, cela fonctionne très bien. Mais après avoir supprimé certaines photos avec l'application 'Photos', mon application tombe en panne.

L'info de crash est:

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

Il semble que le nombre de photos locales rest le même que befoore. Et même après avoir quitté mon application et l'avoir redémarrée, elle se bloque toujours.

Code d'access photo local:

 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] isEqualToSsortingng: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]; } }); 

Si je prends une autre photo avec la camera système, mon application est de nouveau OK.

Cela semble être un bug iOS, comme vous l'avez dit ALAssetsLibrary a renvoyé le mauvais numéro de vos photos afin que vous ayez une erreur hors limites de l'index. La solution de contournement consiste à recharger votre photo comme ceci:

 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]; }; 

L'inscription d'un observateur n'a pas aidé dans mon cas. Les users se plantaient toujours, mais je ne l'ai pas fait. Jusqu'à aujourd'hui.

J'ai trouvé le moyen de résoudre ce problème. C'est un bug dans la photothèque d'Apple à la fin, mais il y a une solution de contournement. Qu'est-ce que vous faites est, vous définissez le filter à la photo, puis à la video, au lieu de laisser les actifs par défaut. Vous l'énumérez ensuite une fois pour chacune, et faites quelques truquages ​​pour vous assurer que vous obtenez ce point final 'à zéro' pour faire toutes les mises à jour dont vous avez besoin. Mon approche actuelle est un peu brouillon mais vous avez l'idée:

 // 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 sortingggers __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 eg 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 eg tableView reload! } }); }); 

C'est tout. Les NSRangeExceptions disparaissent. Au less dans mon cas, ils l'ont fait.

Ce dont vous avez besoin est d'save un observateur pour ALAssetsLibraryChangedNotification pour get les modifications de la bibliothèque. Lorsque la notification se triggers, renumérotez les groupes et le contenu de la bibliothèque d'actifs. Si vous ne vous inscrivez pas à la notification, votre application obtiendra un ancien cliché de la bibliothèque et l'énumération échouera. S'il vous plaît noter également qu'il existe un bug concernant ALAssetsLibraryChangedNotification sous iOS 5.x comme documenté ici: http://www.openradar.me/10484334

J'ai commencé avec la réponse de Qiulang, mais ça n'a pas marché pour moi. Ce qui a fonctionné pour moi est d'appeler le setAssetsFilter 3 fois de suite avec toutes les combinaisons de filters, avant de commencer l'énumération.

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

À iOS 8, j'ai également remarqué que numberOfAssets renvoie un mauvais nombre de photos si certaines d'entre elles ont été supprimées et se trouvent actuellement dans l'album 'Recently Deleted'.

Pour ceux d'entre vous qui remplissent NSArray avec toutes les présentations ALAssetRepresentations et ne veulent pas trop changer votre code, filterz simplement votre tableau avec ce Checker – AssetURLChecker

À votre santé!

La bibliothèque ALAssetsLibrary est dépréciée sur PHAssetsLibrary alors utilisez ce code:

 __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]; } }];