9.1: Predicate in PHAssetCollection fetch options crash

In my app I fetch a photo album by name:


    let fetchOptions = PHFetchOptions()
    fetchOptions.predicate = NSPredicate(format: "title = %@", "SomeAlbumName")
    let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)


This works in iOS 8.x and iOS 9.0 GM, but in 9.1 it crashes with a predicate format error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate in fetch options: localizedTitle == "SomeAlbumName"'


I couldn't find anything on this in the release notes and the docs. Am I missing something obvious? Appreciate any help.

Accepted Reply

This is a bug in the seed and will be fixed in a future beta.

Replies

We are seeing this same issue in the production version of our application from users running iOS 9.1. Seems to be an Apple bug since it works correctly in all other versions < 9.1. We should probably open a radar for it

I have noticed the asset collection has a property named

public var localizedTitle: String? { get }


I wonder if title was deprecated, although I can't find any documentation suggestion that

First thing I tried was to change the predicate to localizedTitle but I got the same crash.


I just created a quick app to demonstrate this crash: https://github.com/Priime/iOS-9.1-fetch-options-predicate-test


Filed radar://22690748

Hi, we've got the same issue. So I can suggest a workaround for you. Instead of fetching needed collection with a predicate, you can fetch all collections and enumerate them to find with needed title.


__block PHAssetCollection *collection = nil;
PHFetchResult *assetCollectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
[assetCollectionFetchResult enumerateObjectsUsingBlock:^(PHAssetCollection * obj, NSUInteger idx, BOOL *stop) {
   if([obj.localizedTitle isEqualToString:@"Your collection title"])
   {
     *stop = YES;
     collection = obj;
   }
}];


It works well.


But I think we should send a bugreport.

Yeah we ended up using something like that as a fallback. As a temporary solution we wrapped the predicate fetch in a try catch and fallback to iterating over all albums to find the correct collection.


Hopefully Apple will fix this bug before shipping iOS 9.1

Same issue for me (iOS 9.1)


Code:


private func initializeAlbum() {
    
        let fetchOptions: PHFetchOptions = PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "title = %@", self.albumName)
        let collection: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
    
        if let firstObject: AnyObject = collection.firstObject {
            self.albumExists = true
            self.assetCollection = collection.firstObject as! PHAssetCollection
            if let ac = self.assetCollection {
                self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
            }
            println("\(self.albumName) album exists")
        }
        else {
            var albumPlaceHolder: PHObjectPlaceholder!
        
            PHPhotoLibrary.sharedPhotoLibrary().performChanges({
            
                let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(self.albumName)
                albumPlaceHolder = request.placeholderForCreatedAssetCollection
            
                }, completionHandler: { (success: Bool, error: NSError!) in
                
                    self.albumExists = success
                    if success {
                        let collection = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([albumPlaceHolder.localIdentifier], options: nil)
                        self.assetCollection = collection.firstObject as! PHAssetCollection
                        if let ac = self.assetCollection {
                            self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
                        }
                        println("\(self.albumName) album made")
                    }
                    else {
                        println("Failed to create \(self.albumName) Album")
                    }
                
            })
        }
    
    }


Error:


'NSInvalidArgumentException', reason: 'Unsupported predicate in fetch options: title == "iFeel"'



For the moment this is a possible solution (in Swift):


let collection: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: nil)

for var k = 0; k < collection.count; k++ {
            let obj: AnyObject! = collection.objectAtIndex(k)
            if obj.title == self.albumName {
                self.albumExists = true
                self.assetCollection = obj as! PHAssetCollection
               if let ac = self.assetCollection {
                    self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
                }
                println("\(self.albumName) album exists")
                break
            }
}

I am going to enumerate them too, but this is dumb and with iCloud Photo Library there actually could be a ton of albums. Hope they fix this soon.

Curious, since PHAssetCollection.fetchAssetCollectionsWithType() doesn't throw, how do you try and catch?

I created an Objective-C class that wraps try / catch in a method and made that class available through the bridging header. That way I can catch the exception 🙂

This is a bug in the seed and will be fixed in a future beta.