我正在用Swift写一个iOS应用,使用Firestore作为数据库。我有一些类代表我的Firestore对象,看起来像这样:
class FirestoreObject: Decodable, Hashable, ObservableObject {
enum CodingKeys: String, CodingKey {
case id
case attributeA = "attribute_a"
case attributeB = "attribute_b"
}
@DocumentID var id: String?
@Published var attributeA: Double
@Published var attributeB: String
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
_id = try container.decode(DocumentID<String>.self, forKey: .id)
self.attributeA = try container.decode(Double.self, forKey: .attributeA)
self.attributeB = try container.decode(String.self, forKey: .attributeB)
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func == (lhs: FirestoreObject, rhs: FirestoreObject) -> Bool {
return lhs.id == rhs.id
}
}
这个模式对我所有的Firestore对象都是一样的。我如何推广这个模式以避免重复自己呢?哈希和==函数可以总是完全相同的,并且init(来自decoder:)将总是完全相同的工作,尽管当然键/属性因对象而异。
我研究了协议和继承,但我对Swift还是新手,我不确定正确的方法。主要的事情是尝试自动提供默认init,它按照我想要的方式工作--它与默认init几乎相同(来自:decoder),Swift为Decodable提供的功能。
2条答案
按热度按时间qoefvg9y1#
Firestore支持Swift的
Codable
协议,这使得Map更加容易:在大多数情况下,您不必编写任何Map代码。只有当您有特殊要求时(例如,仅Map某些文档属性,或将属性Map到名称略有不同的属性),您才需要添加几行代码来告诉Codable要Map哪些字段或Map到哪些属性。我们的文档提供了一个全面的指南,解释了
Codable
的基础知识,以及一些更高级的用例:Map Cloud Firestore data with Swift Codable | Firebase在SwiftUI应用程序中,您希望数据模型是结构体,只有视图模型应该是符合
ObservableObject
的class
。下面是一个例子:
数据模型
查看模型
nfzehxib2#
我认为这里最好的解决方案是添加一个超类,所有Firestore类型都从它继承
然后,您需要在所有子类中添加一个
init(from:)
来解码该子类的特定属性我不认为你可以概括它比这更多,除非你可以使用struct并将它们 Package 在一个符合ObservableObject的泛型类中,但只有对象会被发布,而不是单个属性。
就像
那么实际的类型就很容易实现了