簡體   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