3
votes

Fetching PHAssets is now crashing for me on latest versions of iOS (iOS 9.2 and iOS 9.3). It previously worked fine.

The error I am getting is:

[PHCollectionList canContainCustomKeyAssets]: unrecognized selector sent to instance Terminating app due to uncaught exception 'NSInvalidArgumentException'

The line throwing the exception is:

            PHFetchResult *fetchImage = [PHAsset fetchKeyAssetsInAssetCollection:(PHAssetCollection*)collection options:fetchOptions];

Here is more code, for reference:

Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary");
        if (PHPhotoLibrary_class) {

            PHFetchResult *fetchResult = self.collectionsFetchResults[indexPath.section];
            PHCollection *collection = fetchResult[indexPath.row];

            cell.textLabel.text = collection.localizedTitle;

            PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
            fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
            PHFetchResult *fetchImage = [PHAsset fetchKeyAssetsInAssetCollection:(PHAssetCollection*)collection options:fetchOptions];
            PHAsset *asset = [fetchImage firstObject];

            PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
            options.resizeMode = PHImageRequestOptionsResizeModeExact;

            CGFloat scale = [UIScreen mainScreen].scale;
            CGFloat dimension = 90.0;
            CGSize size = CGSizeMake(dimension*scale, dimension*scale);

            [[PHImageManager defaultManager] requestImageForAsset:asset
                                                       targetSize:size
                                                      contentMode:PHImageContentModeAspectFill
                                                          options:options
                                                    resultHandler:^(UIImage *result, NSDictionary *info) {
                                                        if (result) {
                                                            CGSize itemSize = CGSizeMake(60, 60);
                                                            UIGraphicsBeginImageContextWithOptions(itemSize, NO, 2);
                                                            CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
                                                            [result drawInRect:imageRect];
                                                            cell.imageView.image  = UIGraphicsGetImageFromCurrentImageContext();
                                                            UIGraphicsEndImageContext();
                                                        }
                                                        else{
                                                            UIImage *placeholder = [UIImage imageNamed:@"image-placeholder.jpg"];
                                                            CGSize itemSize = CGSizeMake(60, 60);
                                                            UIGraphicsBeginImageContextWithOptions(itemSize, NO, 2);
                                                            CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
                                                            [placeholder drawInRect:imageRect];
                                                            cell.imageView.image  = UIGraphicsGetImageFromCurrentImageContext();
                                                            UIGraphicsEndImageContext();
                                                        }
                                                    }];
        }
2

2 Answers

4
votes

This issue actually lies here:

PHCollection *collection = fetchResult[indexPath.row];

and then here:

PHAsset *asset = [fetchImage firstObject];

You are fetching the collection using PHCollection and then just assuming all assets are PHAssets without properly checking if this is the case or not.

Actually, PHCollection has two possible subclasses: PHAsset and PHCollectionList, and the PHCollectionList is what is throwing the error here.

Wrap the code after PHCollection *collection = fetchResult[indexPath.row]; with a check for PHAsset, and it should solve the issue:

if ([collection isKindOfClass:[PHAssetCollection class]]) {
//code 
}
0
votes

First, get all assets using PHAsset like

dispatch_async(dispatch_get_main_queue(), ^{     

        AllPhotos=[[NSMutableArray alloc] init];
        PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
        for (PHAsset *asset in result)
        {
            [AllPhotos addObject:asset];

        }
        [self.collectionView reloadData];

        // code here
    });

Not, use the collectionview delegate method like

  PHImageManager *manager = [PHImageManager defaultManager];
    PHAsset *asset = [AllPhotos objectAtIndex:indexPath.row];
    PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init];
    requestOptions.resizeMode   = PHImageRequestOptionsResizeModeExact;
    requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
    requestOptions.synchronous = false;

    //CGFloat scale = 1.5; //or an even smaller one
    if (!manager)
    {
        manager = [[PHCachingImageManager alloc] init];
    }
    if (!requestOptions)
    {
        requestOptions = [[PHImageRequestOptions alloc] init];
    }

    [manager requestImageForAsset:asset
                       targetSize:CGSizeMake(imagesize.width,imagesize.height)
                      contentMode:PHImageContentModeAspectFill
                          options:requestOptions
                    resultHandler:^void(UIImage *image, NSDictionary *info)
     {
         [imageview setImage:image];
     }];

    [cell.contentView addSubview:imageview];