簡體   English   中英

使用Swift推斷類方法中的泛型類型

[英]Infer Generic Type in Class Method with Swift

通用方法是否可以根據正在執行該方法的類來推斷其類型? 我使用CoreData NSManagedObject模型來存儲和檢索本地數據,並且設法使所有通用內容都易於閱讀和使用,除了在一個地方。 如果用戶希望查詢本地數據庫以獲取對象列表,則可以編寫以下行:

let posts: [Post] = Post.all()

這將正確返回數據庫中的“所有” Post對象,但是語法要求在從Post類本身( Post.all() )調用方法的頂部定義類型( [Post] ),這會不必要地感到多余。 是否可以通過從Post類調用all()方法來簡單地定義泛型類型? 我想我可以像這樣創建全局函數來獲取數據:

let posts: [Post] = all()

如果語法如下,那么感覺起來幾乎不那么可讀:

let posts = Post.all()

試圖改善這一點的目的是,使選擇此項目的任何開發人員都可以快速學習結構和樣式,而無需付出太多努力。 而且,這將有望在將來提高常規代碼的可讀性,而不管是有人正在處理它還是僅出於其他原因而正在閱讀它。

為了獲得更多的見解,以下是有關當前結構的更多信息:

//Model.swift - The model base class. All models extend this class.

class Model: NSManagedObject {
    /**
    Some other stuff here
    **/

    //MARK: Fetch
    internal class func fetch<T: Model>(predicate: NSPredicate? = nil) -> [T]? {
        do {
            if let request = NSFetchRequest.FromEntityName(self.entityName) { //Get entity with the name defined in the current class
                request.predicate = predicate
                if let result = try self.context?.executeFetchRequest(request) as? [T] {
                    return result
                }
            }
        }
        catch let error as NSError {
            Log.Error("\(error)")
        }
        return nil
    }

    //MARK: Fetch general
    class func all<T: Model>() -> [T]? {
        if let result: [T] = self.fetch() {
            return result
        }
        Log.warning("No \(self.entityName) found")
        return nil
    }
}

//Post.swift - An example model class. Extends Model.swift

class Post: Model {
    //some fields
}

//Example view controller
class ViewController: UIViewController {
    override func viewDidLoad() {
        let posts: [Post] = Post.all()
        //do stuff
    }
}

如果有人對此有任何想法,請告訴我。 感謝所有幫助!

在一般情況下,類方法即使對於子類也返回“類的類型”的典型方法是使用協議擴展和Self類型。 這是一個示例,將您的方法精簡到最低限度,以使類型檢查按您希望的方式工作:

// define a protocol
protocol ModelType {}
// create a static method on the protocol that returns [Self]
extension ModelType where Self: NSManagedObject {
    static func all() -> [Self]? {
        return [Self]() // do your fetch here
    }
}
// conform to the protocol in your class hierarchy
class Model: NSManagedObject, ModelType {}
class Post: Model {}

let posts = Post.all()
// implicit type of `posts` is `[Post]?`

請注意, all()應該由協議擴展提供,而不是協議的要求。 如果在protocol ModelType內聲明all() ,則不能使其使用動態分派,如果要使用動態類型,則必須這樣做。


另外,請注意,在Swift 3(和macOS 10.12 / iOS 10 / tvOS 10 / watchOS 3)中,Core Data本身定義了一些Swift API快捷方式,以代替您為自己定義的一些快捷方式。 請注意“核心數據的新增功能”中的此示例:

func findAnimals() {
    context.performAndWait({
        let request = Animal.fetchRequest // implicitly NSFetchRequest<Animal>
        do {
            let searchResults = try request.execute()
            // use searchResults ...
        } catch {
            print("Error with request: \(error)")
        }
    })
}

最后,對您選擇的風格進行一些評論...

僅供參考,我按照慣例將所有靜態/類方法中的首字母大寫

試圖改善這一點的目的是,使選擇此項目的任何開發人員都可以快速學習結構和樣式,而無需付出太多努力。 此外,這有望在將來提高常規代碼的可讀性

我不確定打破語言標准約定(例如Swift 3 API指南中建議的小寫方法名稱)是否與您的目標(使其他剛接觸您的代碼庫的開發人員更易於閱讀和參與)的目標兼容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM