In Swift 3, PHFetchResult
is a generic class. (It has been in ObjC since the iOS 9 SDK last year, and Swift 3 now imports ObjC generics.) Generic types must always be specialized. In ObjC a generic class works with or without a type parameter (that is, you can have a PHFetchResult<SomeObjectType *> *
or a PHFetchResult *
, and in the latter case the type parameter is assumed to be id
). But in Swift you can't — you always have to declare an element type.
So, if you're declaring a variable to hold Photos fetch results, you need to declare the expected object type of those fetch results.
Your first one looks like it's expected to be a list of albums — perhaps to be fetched via fetchTopLevelUserCollections(with:)
? So its type should be PHFetchResult<PHCollection>
or PHFetchResult<PHAssetCollection>
depending on exactly which fetch method you're using and what you intend to do with it next.
The second is an array of fetch results? That alone sounds fishy given the variable name cameraRoll
. If you just want to fetch all the assets in the camera roll, just use fetchAssets(in:options:)
, passing the camera roll as the collection to fetch from. (You can get the camera roll with fetchAssetCollections(with:subtype:options:)
, using the .smartAlbum
type and .smartAlbumUserLibrary
subtype.)
Whether it's a single fetch result or an array of fetch results, if you expect the fetch(es) to contain assets the type (or element type of the array) should be PHFetchResult<PHAsset>
.
A second, more minor, problem with your code is that you're creating dummy, empty fetch results only for them to (presumably) be overwritten by an actual fetch later. (PHFetchResult
is an immutable collection, so its initializer creates an empty collection that you can't usefully do anything with.)
You'd be better off declaring those variables with optional types (or, if you plan to initialize them early and expect all code paths after that to come after initialization, implicitly unwrapped optional types). Or, if it fits your use case, make them lazy:
class PhotosAlbumsController: UITableViewController {
var galleryController: GalleryController!
lazy var albums = PHCollection.fetchTopLevelUserCollections(with: nil)
// ^- implicitly typed PHFetchResult<PHCollection>
lazy var cameraRoll = PHAssetCollection.fetchAssetCollections(with: .smartAlbum,
subtype: .smartAlbumUserLibrary, options: nil).firstObject!
// ^- implicitly typed PHAssetCollection
// safe to force unwrap because there's always a Camera Roll / Saved Photos album
// ...
}
The one thing to watch out for with lazy initialization here (whether you do it with lazy
or by directly fetching at some other time) is to make sure you have user authorization for Photos access first, and/or make sure you register as a PHPhotoLibrary
observer first. If you fetch before getting authorization, your fetches will be empty. If you register as an observer first, your fetches will still be empty to start with, but as soon as the user accepts authorization you'll get a photoLibraryDidChange
call that populates them.