gpt4 book ai didi

ios - 协议(protocol)中的默认初始化程序需要不需要的可变属性

转载 作者:行者123 更新时间:2023-11-28 08:13:33 27 4
gpt4 key购买 nike

在 Swift 3 中:假设您希望模型在整个应用程序中都是值类型(结构)。但是您还希望使用 Core Data/Realm 来持久化上述模型,这需要您创建类。然后,您可以使用 JSON 将结构转换为类,反之亦然(这需要结构和类都支持 JSON 反序列化和序列化)。

如果你不必在两个地方编写 JSON 反序列化(和序列化类似,但我在这里专注于反序列化),而是在 protocol ,你的结构和类都使用。

使用结构,我们希望我们的 JSON 模型具有不可变字段,因此所有属性都是 let常数。但是使用 protocol反序列化的实现不允许这个 AFAIK。

下面的代码示例有效,但它很丑陋,因为所有不需要的要求 (UR) 都标记在代码的注释中。

struct JSON {
let json: [String: Any]
func value<Value>(_ key: String) throws -> Value {
guard let value = json[key] as? Value else { throw NSError() }
return value
}
}

protocol JSONDeserializable {
init(json: JSON) throws
}

protocol UserModel: JSONDeserializable {
var username: String { get set } // Unwanted requirement (UR) #1: property needs "set" so that it can be initialized within protocol
init() // UR2: needs empty init, because of default implementation of `init(json: JSON)` in `extension UserModel`
}

extension UserModel {
init(json: JSON) throws {
self.init() // UR3: Needs to call this otherwise compilation error: `'self' used before chaining to another self.init requirement`
username = try json.value("username")
}
}

struct UserStruct: UserModel {
// UR4: property cannot be `let`, beause of `set` in protocol.
var username: String = "" // UR5: Property have to have default value because of it being a empty init
init() {}
}

final class UserClass: NSObject, UserModel {
// UR6: analogue with UR4
var username: String = "" // UR7: analogue with UR5
}

let json: JSON = JSON(json: ["username": "Sajjon"])
let u1 = try UserStruct(json: json)
let u2 = try UserClass(json: json)
print(u1.username) // prints "Sajjon"
print(u2.username) // prints "Sajjon"

是否有另一种方法可以实现这一目标,减少不必要的需求?或者零 UR 的最佳解决方案? 🙄

最佳答案

感谢@hamish 指出的内容,最好的解决方案是(其中 struct JSONprotocol JSONDeserializable 与问题中的相同)。这不是一个完美的解决方案,因为您必须实现类的初始化程序。简洁的部分是您不必为该结构实现任何初始化器,因为它隐含了一个初始化器。

protocol UserModel: JSONDeserializable {
var username: String { get }
var firstname: String { get }
var country: String { get }
init(
username: String,
firstname: String,
country: String
)
}

extension UserModel {
init(json: JSON) throws {
self.init(
username: try json.value("username"),
firstname: try json.value("firstname"),
country: try json.value("country")
)
}
}

struct UserStruct: UserModel {
let username: String
let firstname: String
let country: String
// struct has default initializer
}

final class UserClass: UserModel {
let username: String
let firstname: String
let country: String
init(
username: String,
firstname: String,
country: String
) {
self.username = username
self.firstname = firstname
self.country = country
}
}

let json: JSON = JSON(json: [
"username": "Sajjon",
"firstname": "Alexander",
"country": "Sweden"
])
let u1 = try UserStruct(json: json)
let u2 = try UserClass(json: json)
print(u1.username) // prints "Sajjon"
print(u2.username) // prints "Sajjon"

关于ios - 协议(protocol)中的默认初始化程序需要不需要的可变属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43096305/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com