Search code examples
swiftgenericsswift4extension-methodsphphotolibrary

PHFetchResult extension that uses it's Generic ObjectType?


I'm trying to add an extension to PHFetchResult to pull the result objects out as a correctly typed array - and so far I can't figure out how to avoid the replication seen below. Aside from the type constraint the following extensions are identical. If I use PHObject as the constraint it would work, but the result would need to be cast to the more specific type...

extension PHFetchResult where ObjectType == PHAsset {
    var objects: [ObjectType] {
        var _objects: [ObjectType] = []
        enumerateObjects { (object, _, _) in
            _objects.append(object)
        }
        return _objects
    }
}    
extension PHFetchResult where ObjectType == PHCollection {
    var objects: [ObjectType] {
        var _objects: [ObjectType] = []
        enumerateObjects { (object, _, _) in
            _objects.append(object)
        }
        return _objects
    }
}    
extension PHFetchResult where ObjectType == PHAssetCollection {
    var objects: [ObjectType] {
        var _objects: [ObjectType] = []
        enumerateObjects { (object, _, _) in
            _objects.append(object)
        }
        return _objects
    }
}

Solution

  • This is a general issue with generic types defined in ObjC and imported to Swift. Some relevant compiler bugs:

    In short: ObjC generics are type-erasing, Swift generics are type-preserving. You need the latter for tasks like defining type-constrained extensions, but you can't because Swift doesn't know anything about the ObjectType of any particular PHFetchResult instance.

    The swift-evolution proposal that brought widespread ObjC generics import to Swift 3 included a provision for letting ObjC classes provide information about their generic type parameters at runtime... but as of today, that provision has never been implemented.

    AFIAK, there's not really a solution to this problem (short of working on the Swift compiler project to improve ObjC generics support), nor similar problems like making PHFetchResult conform to Sequence or Collection.

    (I've tried a few angles on extending PhotoKit classes to be more Swifty myself, without much success. About the only thing I haven't tried — largely because it's such a drastic measure — is wrapping/replacing large chunks of the API. In theory, though, you could wrap PHFetchResult in a non-generic ObjC class, then wrap that in a generic Swift type, and replace all of the PhotoKit fetch methods with ones that provide appropriately specialized versions of your wrapper type.)