Swift 2.x 到 Swift 3,XCode 抱怨:无法转换 PHFetchResult 类型的值

Zip*_*tte 0 swift photokit swift3

这是我的代码:

    var galleryController: GalleryController!
    var albums: PHFetchResult = PHFetchResult()
    var cameraRoll: [PHFetchResult] = [PHFetchResult]()

    albums=getAlbums()
    cameraRoll=getcameraRoll()

func getAlbums()->PHFetchResult<AnyObject>
{
    let fetchOptions=PHFetchOptions()
    fetchOptions.predicate=NSPredicate(format:"estimatedAssetCount > 0")
    return PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.album, subtype: PHAssetCollectionSubtype.albumSyncedAlbum, options: fetchOptions) as! PHFetchResult<AnyObject>
}    

func getcameraRoll()->[PHFetchResult<AnyObject>]
{
    self.photosFromCameraRoll=PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)
    return [self.photosFromCameraRoll]
}
Run Code Online (Sandbox Code Playgroud)

对于var albums: PHFetchResult = PHFetchResult()Xcode 正在使用此消息的行:“无法将类型的值转换PHFetchResult<_>为指定的 PHFetchResult”

对于行var cameraRoll: [PHFetchResult] = [PHFetchResult]()Xcode 也有相同的消息:“无法将类型的值转换PHFetchResult<_>为指定的 PHFetchResult”

ric*_*ter 5

在 Swift 3 中,PHFetchResult是一个泛型类。(它从去年的 iOS 9 SDK 开始就在 ObjC 中,而Swift 3 现在导入 ObjC 泛型。)泛型类型必须始终是专门化的。在 ObjC 中,泛型类可以使用或不使用类型参数(也就是说,您可以有 aPHFetchResult<SomeObjectType *> *或 a PHFetchResult *,在后一种情况下,类型参数假定为id)。但是在 Swift 中你不能——你总是必须声明一个元素类型。

因此,如果您要声明一个变量来保存照片提取结果,则需要声明这些提取结果的预期对象类型。

  • 你的第一个看起来像是专辑列表——也许可以通过fetchTopLevelUserCollections(with:)? 所以它的类型应该是PHFetchResult<PHCollection>或者PHFetchResult<PHAssetCollection>取决于你正在使用的获取方法以及你接下来打算用它做什么。

  • 第二个是获取结果的数组?考虑到变量 name ,仅此一项就听起来很可疑cameraRoll。如果您只想获取相机胶卷中的所有资产,只需使用fetchAssets(in:options:),将相机胶卷作为要从中获取的集合传递。(您可以使用fetchAssetCollections(with:subtype:options:),使用.smartAlbum类型和.smartAlbumUserLibrary子类型获取相机胶卷。)

    无论是单个提取结果还是提取结果数组,如果您希望 fetch(es) 包含资产,则类型(或数组的元素类型)应该是PHFetchResult<PHAsset>


您的代码的第二个更次要的问题是您正在创建虚拟的、空的提取结果,只是为了它们(可能)稍后被实际提取覆盖。(PHFetchResult是一个不可变的集合,所以它的初始化器创建了一个空的集合,你不能用它做任何有用的事情。)

您最好使用可选类型声明这些变量(或者,如果您计划尽早初始化它们并期望之后的所有代码路径都在初始化之后出现,则隐式解包可选类型)。或者,如果它适合您的用例,让它们变得懒惰:

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

在这里使用延迟初始化需要注意的一件事(无论是使用lazy还是在其他时间直接获取)是确保您首先获得照片访问的用户授权,和/或确保您首先注册为PHPhotoLibrary观察者. 如果您在获得授权之前提取,您的提取将是空的。如果您首先注册为观察者,您的提取一开始仍然是空的,但是一旦用户接受授权,您就会收到一个photoLibraryDidChange填充它们的电话。