问题:
更新 Firebase 中特定对象的属性。为此,我只想更新一个对象内的一个值,而不必与当前对象交互。 firebase 的必需部分,除了集合和文档之外,还有 key 和 new value
我想出了一个可行的实现 - 我想要一些改进的想法。 特别是那里,static func createEmpty() -> Self,这让我很困扰。初始化模型以查找密钥对我来说似乎效率不高。我希望有一个敏捷的好人能给我指路。
外观如下:
这个协议将是key property reader:
protocol KeyPathValueReadable {
static func createEmpty() -> Self
}
extension KeyPathValueReadable {
fileprivate subscript<T:Any>(at path : KeyPath<Self,T> ) -> String{
print(self[keyPath: path])
return "\(self[keyPath: path])"
}
func readValue<T : Any & Hashable>(at keyPath : KeyPath<Self,T>) -> String{
let mirror = Mirror(reflecting: self)
var dict : [T: String] = [:]
for case let (label, value) in mirror.children {
if let label = label {
dict[value as! T] = label
}
}
return dict[self[keyPath: keyPath]] ?? "no key at path"
}
}
这是要更新的模型示例:
struct UserModel : Codable, KeyPathValueReadable {
var name : String
static func createEmpty() -> Self {
return Self.init(name: "")
}
}
这里是客户端实现和使用:
protocol UpdateDataClientDelegate {
associatedtype D : Codable & KeyPathValueReadable
}
extension UpdateDataClientDelegate {
func update<T : Hashable>(in collection : String, for document : String, at path : KeyPath<D,T>, newValue : Any) {
let key = D.createEmpty().readValue(at: path)
print(key)
//update key with newValue
}
}
struct UpdateUserClient : UpdateDataClientDelegate {
typealias D = UserModel
}
let client = UpdateUserClient()
client.update(in: "pouf", for: "plaf", at: \.name, newValue: "chocolate")
编辑
如果存在类型冗余,先前的实现会导致字典中的覆盖。 为了解决这个问题,我应用了 createEmpty() 还必须为我们查找名称的变量设置一个值。
因此,我在可读键的扩展名中添加了一个下标 - 因此它会为路径设置一个值。
extension KeyPathValueReadable {
subscript<T>(dynamicMember path: WritableKeyPath<Self, T>) -> T{
get { self[ keyPath: path] }
set { self[ keyPath: path ] = newValue }
}
}
然后就可以这样使用了:
func update<T : Hashable>(in collection : String, for document : String, at path : WritableKeyPath<D,T>, with value : T) throws {
Task {
var dict = [String : T]()
var object = D.createEmpty()
object[dynamicMember: path] = value
dict[object.readValue(at: path)] = value
try await apiClient.updateData(dict)
}
}