Search code examples
iosobjective-cphasset

[PHCollectionList canContainCustomKeyAssets]: unrecognized selector sent to instance


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

Solution

  • 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 
    }