【问题标题】:Swift 2.x to swift 3, XCode complaining : Cannot convert value of type PHFetchResultSwift 2.x 到 Swift 3,XCode 抱怨:无法转换 PHFetchResult 类型的值
【发布时间】:2026-01-27 00:45:02
【问题描述】:

这是我的代码:

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

对于var albums: PHFetchResult = PHFetchResult() 行,Xcode 遇到此消息:“无法将 PHFetchResult&lt;_&gt; 类型的值转换为指定的 PHFetchResult”

对于 var cameraRoll: [PHFetchResult] = [PHFetchResult]() 行,Xcode 也出现相同的消息:“无法将 PHFetchResult&lt;_&gt; 类型的值转换为指定的 PHFetchResult”

【问题讨论】:

  • 您可能想向我们提供一些有关“PHFetchResult”的详细信息?

标签: swift swift3 photokit


【解决方案1】:

在 Swift 3 中,PHFetchResult 是一个泛型类。 (自去年的 iOS 9 SDK 以来,它一直在 ObjC 中,Swift 3 now imports ObjC generics。)泛型类型必须始终是专门的。在 ObjC 中,泛型类可以使用或不使用类型参数(也就是说,您可以使用 PHFetchResult&lt;SomeObjectType *&gt; *PHFetchResult *,在后一种情况下,类型参数假定为 id)。但是在 Swift 中你不能——你总是必须声明一个元素类型。

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

  • 您的第一个看起来应该是专辑列表 - 可能通过 fetchTopLevelUserCollections(with:) 获取?因此,它的类型应该是 PHFetchResult&lt;PHCollection&gt;PHFetchResult&lt;PHAssetCollection&gt;,具体取决于您正在使用的 fetch 方法以及您接下来打算用它做什么。

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

    无论是单个 fetch 结果还是一组 fetch 结果,如果您希望 fetch(es) 包含资产,则类型(或数组的元素类型)应为 PHFetchResult&lt;PHAsset&gt;


您的代码的第二个更小问题是,您正在创建虚拟的、空的提取结果,只是为了(可能)被稍后的实际提取覆盖。 (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

    // ...
}

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

【讨论】: