繁体   English   中英

如何键入检查通用然后在swift中转换为它?

[英]How can I type check a generic then cast to it in swift?

我喜欢这篇文章中提出的关于制作数据库无关,面向协议的代码的想法。

所以说我有一个协议,如:

protocol Database {
    func loadObjects<T>(matching query: Query) -> [T]
    func loadObject<T>(withID id: String) -> T?
    func save<T>(_ object: T)
}

其中Query是具有过滤器和排序说明符的结构。

然后,给定一个持久性框架,例如Realm或CoreData,我可以支持这个协议,如下:

extension NSManagedObjectContext: Database {
    ...
}

extension Realm: Database {
    ...
}

extension MockedDatabase: Database {
    ...
}

extension UITestingDatabase: Database {
    ...
}

当我想要使用CoreData时会出现问题。

如果我们看一下方法:

func loadObjects<T>(matching query: Query) -> [T]

我无法将'强制转换'到NSManagedObject。

例如,我想要的实现可能是这样的:

extension NSManagedObjectContext: Database {

    func loadObjects<T>(matching query: Query<T>) -> [T] {

        // you need a fetch request for these models.  This guard statement compiles.  How do we make it work with NSFetchRequestResult however?
        guard T.self is NSManagedObject.Type else {
            return []
        }

        // This line below Fails compiling.  Type 'T' does not conform to protocol 'NSFetchRequestResult'
        var request = NSFetchRequest<T>(entityName: String(describing: T))

        // then set sortDescriptors and predicate, etc.

        var objects: [T] = []
        self.performAndWait {
            do {
                if let results = try self.fetch(request!) as? [T] {
                    objects = results
                }

            } catch let error {
                print("Error fetching: \(error.localizedDescription)")
            }
        }
        return objects
    }
}

因此,如果我可以确定T的类型是否是一种NSManagedObject,那么是否可以通过'将'T'转换为可以工作的东西来实例化NSFetchRequest? 似乎我无法施放或迫使T成为任何东西。

数据库是一种与技术无关的协议,因此不应该对核心数据有任何了解。 如果我需要更改数据持久性框架,我想这样做。

我怎么能在Swift中完成这个? 我是否必须添加Model协议以返回将用于我支持的给定框架的选项? 或者让他们支持NSFetchRequestResult? 我宁愿只有协议的实现需要关心持久性框架的细节。

例如,不是在运行时检查类型,而是在编译 约束类型

extension NSManagedObjectContext: Database {

    func loadObjects<T: NSManagedObject>(matching query: Query<T>) -> [T] {

        let request = NSFetchRequest<T>(entityName: String(describing: T.self))

        var objects = [T]()
        self.performAndWait {
            do {
                objects = try self.fetch(request) // a generic fetch request returns an array of the generic type or throws an error
            } catch let error {
                print("Error fetching: \(error.localizedDescription)")
            }
        }
        return objects
    }
}

看起来我可以回答我自己的问题。 人们可以通过重载它们进一步约束泛型类型,所以调用代码可以保持不变,但什么被调用取决于你进入它的类型。

下面的代码在操场上演示了这一点:

public protocol Action {
    func doSomething<T>(to object: T)
}

public class MyActor {

}

extension MyActor: Action {

    // works for any type
    public func doSomething<T>(to object: T) {
        print("was generic")
    }

    // but if you constrain the type and your object fits that constraint...
    // this code is called (same method signature)
    public func doSomething<T: NSObject>(to object: T) {
        print("was an object")
    }
}

class MyObject: NSObject {
    var name: String = "Object"
}

struct MyStruct {
    var name: String = "Struct"
}

let actor = MyActor()
let object = MyObject()
let value = MyStruct()

actor.doSomething(to: value) // prints 'was generic'
actor.doSomething(to: object)  // prints 'was an object'

所以在原始示例中,我将支持Database for CoreData:

extension NSManagedObjectContext: Database {

    func loadObjects<T>(matching query: Query<T>) -> [T] {
       return [] // return an empty array because we only support NSManagedObject types
    }

    func loadObjects<T: NSManagedObject>(matching query: Query<T>) -> [T] {

        let request = NSFetchRequest<T>(entityName: String(describing: T.self))

        var objects = [T]()
        self.performAndWait {
            do {
                objects = try self.fetch(request) // a generic fetch request returns an array of the generic type or throws an error
            } catch let error {
                print("Error fetching: \(error.localizedDescription)")
            }
        }
        return objects
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM