使用Swift

时间:2016-09-19 21:50:07

标签: ios swift generics

泛型方法是否可以根据执行它的类来推断其类型?我使用CoreData NSManagedObject模型来存储和检索本地数据,并设法以易于阅读和可用的方式使一切通用,除了在一个地方。如果用户希望查询本地数据库以获取对象列表,他将编写以下行:

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

这将正确返回数据库中的“all”Post对象,但语法要求在从[Post]类本身调用方法之前定义类型(Post){{{ 1}}),感觉不必要的冗余。有没有办法只通过调用Post.all()类中的all()方法来定义泛型类型?我想我可以创建用于获取数据的全局函数,如下所示:

Post

如果语法如下,这种感觉几乎不可读:

let posts: [Post] = all()

尝试改进这一点的重点在于,任何接受这个项目的开发人员都可以快速学习结构和风格而不需要太多努力。此外,这将有望在将来提高一般代码的可读性,无论是否有人正在处理它或只是出于其他原因阅读它。

有关更多信息,请参阅以下有关当前结构的更多信息:

let posts = Post.all()

如果有人对此有所了解请告诉我。感谢所有帮助!

1 个答案:

答案 0 :(得分:5)

在一般情况下,类方法返回的典型方式"类的类型"即使对于子类,也要使用协议扩展和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()应由协议扩展提供,但是协议的要求。如果您在all()内声明protocol ModelType,则无法使用动态调度,如果要使用动态类型,则必须使用动态调度。

另外,请注意,在Swift 3(以及macOS 10.12 / iOS 10 / tvOS 10 / watchOS 3)中,Core Data本身定义了一些Swift API快捷方式,这些快捷方式取代了您自己定义的一些快捷方式。请注意What's New in Core Data中的此示例:

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)")
        }
    })
}

最后,对你选择风格的一些评论...

  

fyi我将所有静态/类方法中的第一个字母大写为常规

  

尝试改进这一点的重点在于,任何接受这个项目的开发人员都可以快速学习结构和风格而不需要太多努力。此外,这有望在未来提高通用代码的可读性

我不确定违反语言标准约定(例如Swift 3 API Guidelines中推荐的小写方法名称)与您的目标非常相容,这使得其他开发人员对您的代码库不熟悉阅读并参与。