pka*_*amb 28 xcode warnings swift xcode12
运行 Xcode 12,我的 Swift 5 Xcode 项目现在会在 a Decodable
orCodable
类型声明let
具有初始值的常量时发出警告。
struct ExampleItem: Decodable {
let number: Int = 42 // warning
}
Run Code Online (Sandbox Code Playgroud)
不可变属性不会被解码,因为它是用无法覆盖的初始值声明的
Xcode 建议将 更改let
为 a var
:
修复:改为使属性可变
var number: Int = 42
Run Code Online (Sandbox Code Playgroud)
它还建议修复:
修复:通过初始化程序设置初始值或明确定义一个 CodingKeys 枚举,包括一个“标题”案例以消除此警告
这个新警告的目的是什么?应该注意还是忽略?这种类型的警告可以静音吗?
应该实施 Xcode 的修复吗?或者有更好的解决方案吗?
小智 42
诺亚的解释是正确的。这是错误的常见来源,并且由于 Codable 综合的“神奇”行为,发生的事情并不是很明显,这就是我向编译器添加此警告的原因,因为它使您注意到该属性不会解码并让您明确调用它,如果这是预期的行为。
正如 fix-it 所解释的那样,如果您想使此警告静音,您有几个选择 - 您选择哪一个取决于您想要的确切行为:
init
:struct ExampleItem: Decodable {
let number: Int
init(number: Int = 42) {
self.number = number
}
}
Run Code Online (Sandbox Code Playgroud)
这将允许number
解码,但您也可以传递ExampleItem
使用默认值的实例。
您也可以init
在解码期间直接在内部使用它:
struct ExampleItem: Decodable {
let number: Int
private enum CodingKeys: String, CodingKey {
case number
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
number = try container.decodeIfPresent(Int.self, forKey: .number) ?? 42
}
}
Run Code Online (Sandbox Code Playgroud)
这将允许number
解码,但42
如果解码失败,则用作默认值。
var
,但您也可以将其设为a private(set) var
:struct ExampleItem: Decodable {
let number: Int
private enum CodingKeys: String, CodingKey {
case number
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
number = try container.decodeIfPresent(Int.self, forKey: .number) ?? 42
}
}
Run Code Online (Sandbox Code Playgroud)
使它成为 avar
将允许number
被解码,但它也将允许调用者修改它。通过将其标记为private(set) var
代替,您可以根据需要禁止此操作。
CodingKeys
枚举:struct ExampleItem: Decodable {
var number: Int = 42
}
Run Code Online (Sandbox Code Playgroud)
这将防止number
被解码。由于枚举没有大小写,这让编译器清楚地知道没有要解码的属性。
出现此警告是因为具有初始值的不可变属性不参与解码 - 毕竟,它们是不可变的并且它们具有初始值,这意味着初始值永远不会改变。
例如,考虑以下代码:
struct Model: Decodable {
let value: String = "1"
}
let json = """
{"value": "2"}
"""
let decoder = JSONDecoder()
let model = try! decoder.decode(Model.self, from: json.data(using: .utf8)!)
print(model)
Run Code Online (Sandbox Code Playgroud)
这实际上会打印Model(value: "1")
,即使我们给它的 jsonvalue
是"2"
.
事实上,您甚至不需要在您正在解码的数据中提供值,因为它无论如何都有一个初始值!
let json = """
{}
"""
let decoder = JSONDecoder()
let model = try! decoder.decode(Model.self, from: json.data(using: .utf8)!)
print(model) // prints "Model(value: "1")"
Run Code Online (Sandbox Code Playgroud)
将值更改为 var 意味着它将正确解码:
struct VarModel: Decodable {
var value: String = "1"
}
let json = """
{"value": "2"}
"""
let varModel = try! decoder.decode(VarModel.self, from: json.data(using: .utf8)!)
print(varModel) // "VarModel(value: "2")"
Run Code Online (Sandbox Code Playgroud)
如果您看到此错误,则表示您的代码在解码时从未正确解析相关属性。如果您将其更改为 var,则该属性将被正确解析,这可能正是您想要的 - 但是,您应该确保您正在解码的数据始终具有该键集。例如,这将引发异常(并且由于我们正在使用而崩溃try!
):
let json = """
{}
"""
let decoder = JSONDecoder()
struct VarModel: Decodable {
var value: String = "1"
}
let varModel = try! decoder.decode(VarModel.self, from: json.data(using: .utf8)!)
Run Code Online (Sandbox Code Playgroud)
总之,Xcode 的建议在许多情况下可能是可行的,但您应该逐案评估将属性更改为 a 是否var
会破坏您的应用程序的功能。
如果您希望属性始终返回硬编码的初始值(这就是现在发生的情况),请考虑将其设为计算属性或惰性变量。
归档时间: |
|
查看次数: |
3265 次 |
最近记录: |