在 swift 中使用“默认值”创建非可选 Codable 的最佳方法
Best approach to create Non-optional Codable with `default values` in swift
我知道 class
和 struct
的基本概念,但哪个更有效地为 API 创建模型以获取数据并告诉我优缺点。
以前我不使用可选的模型。相反,我给它一些价值。即
class CompanyInfo : Codable {
var NameEn : String = ""
var CityEn : String = ""
var Website : String = ""
var Email : String = ""
var Phone : String = ""
var Fax : String = ""
}
但是当它从 API 获得一些 null
值时。即 "Fax": null
然后应用程序崩溃,因为它无法使用以下行解析数据
let data = try JSONDecoder().decode(dataModel.self, from: dataSet)
定义模型的最佳方法是什么,这样我就不需要解包可选值或给它默认值。
如果数据模型反映了 API ("Don't make me think") 的 JSON 响应,任何未来的同事都会感谢您。此外,现在您不想拥有可选值 - 在 3 周内您可能需要它们 - 然后您会进行一些丑陋的检查:
if companyInfo.fax == "default" {
// Hey it's the default value but this indicates that the value is optional and nil
}
但是,这是可行的:
顺便说一句 - 还阅读了有关 属性 名称的 Swift 命名约定。
您可以使用默认值实现自定义解码器:
class CompanyInfo : Codable {
var NameEn: String
var CityEn: String
var Website: String
var Email: String
var Phone: String
var Fax: String
required init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.NameEn = try container.decodeIfPresent(String.self, forKey: .NameEn) ?? "Default"
self.CityEn = try container.decodeIfPresent(String.self, forKey: .CityEn) ?? "Default"
self.Website = try container.decodeIfPresent(String.self, forKey: .Website) ?? "Default"
self.Email = try container.decodeIfPresent(String.self, forKey: .Email) ?? "Default"
self.Phone = try container.decodeIfPresent(String.self, forKey: .Phone) ?? "Default"
self.Fax = try container.decodeIfPresent(String.self, forKey: .Fax) ?? "Default"
}
}
}
与问题无关,但很重要注意:
在Swift中,只有Types
个名字应该以大写字母开头。如果您继续这样命名变量,如果您决定使用 CoreData
或与其他 Swift 开发人员合作,总有一天您将遇到严重的重构问题。
对于更有效地使用 class
或 struct
,没有这样的答案。这取决于您的需要、应用程序的需求及其编码结构。
如果您必须在运行时处理可选值,这可能是我认为的最佳方法。
我更愿意在
上使用 struct
struct YOUR_MODEL_NAME : Codable {
var NameEn : String?
var CityEn : String?
var Website : String?
var Email : String?
var Phone : String?
var Fax : String?
enum CodingKeys: String, CodingKey {
case NameEn = "YOUR_KEY_FOR_NameEn"
case CityEn = "YOUR_KEY_FOR_CityEn"
case Website = "YOUR_KEY_FOR_Website"
case Email = "YOUR_KEY_FOR_Email"
case Phone = "YOUR_KEY_FOR_Phone"
case Fax = "YOUR_KEY_FOR_Fax"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
NameEn = try values.decodeIfPresent(String.self, forKey: .NameEn)
CityEn = try values.decodeIfPresent(String.self, forKey: .CityEn)
Website = try values.decodeIfPresent(String.self, forKey: .Website)
Email = try values.decodeIfPresent(String.self, forKey: .Email)
Phone = try values.decodeIfPresent(String.self, forKey: .Phone)
Fax = try values.decodeIfPresent(String.self, forKey: .Fax)
}
}
我知道 class
和 struct
的基本概念,但哪个更有效地为 API 创建模型以获取数据并告诉我优缺点。
以前我不使用可选的模型。相反,我给它一些价值。即
class CompanyInfo : Codable {
var NameEn : String = ""
var CityEn : String = ""
var Website : String = ""
var Email : String = ""
var Phone : String = ""
var Fax : String = ""
}
但是当它从 API 获得一些 null
值时。即 "Fax": null
然后应用程序崩溃,因为它无法使用以下行解析数据
let data = try JSONDecoder().decode(dataModel.self, from: dataSet)
定义模型的最佳方法是什么,这样我就不需要解包可选值或给它默认值。
如果数据模型反映了 API ("Don't make me think") 的 JSON 响应,任何未来的同事都会感谢您。此外,现在您不想拥有可选值 - 在 3 周内您可能需要它们 - 然后您会进行一些丑陋的检查:
if companyInfo.fax == "default" {
// Hey it's the default value but this indicates that the value is optional and nil
}
但是,这是可行的:
顺便说一句 - 还阅读了有关 属性 名称的 Swift 命名约定。
您可以使用默认值实现自定义解码器:
class CompanyInfo : Codable {
var NameEn: String
var CityEn: String
var Website: String
var Email: String
var Phone: String
var Fax: String
required init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.NameEn = try container.decodeIfPresent(String.self, forKey: .NameEn) ?? "Default"
self.CityEn = try container.decodeIfPresent(String.self, forKey: .CityEn) ?? "Default"
self.Website = try container.decodeIfPresent(String.self, forKey: .Website) ?? "Default"
self.Email = try container.decodeIfPresent(String.self, forKey: .Email) ?? "Default"
self.Phone = try container.decodeIfPresent(String.self, forKey: .Phone) ?? "Default"
self.Fax = try container.decodeIfPresent(String.self, forKey: .Fax) ?? "Default"
}
}
}
与问题无关,但很重要注意:
在Swift中,只有Types
个名字应该以大写字母开头。如果您继续这样命名变量,如果您决定使用 CoreData
或与其他 Swift 开发人员合作,总有一天您将遇到严重的重构问题。
对于更有效地使用 class
或 struct
,没有这样的答案。这取决于您的需要、应用程序的需求及其编码结构。
如果您必须在运行时处理可选值,这可能是我认为的最佳方法。
我更愿意在
上使用struct
struct YOUR_MODEL_NAME : Codable {
var NameEn : String?
var CityEn : String?
var Website : String?
var Email : String?
var Phone : String?
var Fax : String?
enum CodingKeys: String, CodingKey {
case NameEn = "YOUR_KEY_FOR_NameEn"
case CityEn = "YOUR_KEY_FOR_CityEn"
case Website = "YOUR_KEY_FOR_Website"
case Email = "YOUR_KEY_FOR_Email"
case Phone = "YOUR_KEY_FOR_Phone"
case Fax = "YOUR_KEY_FOR_Fax"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
NameEn = try values.decodeIfPresent(String.self, forKey: .NameEn)
CityEn = try values.decodeIfPresent(String.self, forKey: .CityEn)
Website = try values.decodeIfPresent(String.self, forKey: .Website)
Email = try values.decodeIfPresent(String.self, forKey: .Email)
Phone = try values.decodeIfPresent(String.self, forKey: .Phone)
Fax = try values.decodeIfPresent(String.self, forKey: .Fax)
}
}