字典应该转换为 class 还是 Swift 中的结构?
Should a dictionary be converted to a class or struct in Swift?
我正在开发一个本机 iOS 应用程序,该应用程序从我们也可以控制的 Web 服务接收 JSON 格式的数据。计划是在大约 18 个月内更换后端数据库以支持不同的平台。
考虑到这一点,我们希望确保 iOS 应用能够相对容易地适应新的数据源,特别是因为我们可能会更改从服务器通过 JSON.
有两个目标:
为每个 PHP 请求创建一个位置,如果需要可以在其中修改密钥。这将避免挖掘代码以找到诸如 job["jobNumber"]
.
之类的东西
清理我们现有的代码以消除像 job["jobNumber"]
.
这样的引用
我们都是 Swift 的新手,没有 Objective-C 经验,但我认为 Struct 或 Class 适合创建像 job.jobNumber
这样的引用.
应该将字典转换为 class 还是结构?代表采用如下所示的 Dictionary<String, String>
并将其转换为推荐类型的可重用方法的示例代码将非常有帮助。
示例字典:
job = {
"jobNumber" : "1234",
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"
}
想要的结果:
println("job name is \(job.name)")
// prints: job name is Awards Ceremony
我一般都是利用值类来实现你想做的事情。在我的项目中,我做了如下操作:
protocol Request : class {
func toDictionary() -> [String : String]
}
protocol Response : class {
init(dictionary: [String : String])
}
class MyRequest : Request {
var var1: Int
var var2: String
//Other stuff in class...
func toDictionary() -> [String : String] {
//Convert the value to dictionary and return
}
}
class MyResponse : Response {
var var1: String
var var2: Int
//You could have nested object as members
var innerObject: MyInnerResponseClass
//Other stuff in class...
var someCalculatedProperty: String {
return //Calculate property value
}
required init(dictionary: [String : String]) {
//Initialize class from dictionary
}
}
class MyInnerResponseClass: Response {
//Class definition here...
}
对于可用作请求和响应的对象,您可以实现这两种协议。
您只需要编写一次翻译代码,就可以在任何地方轻松使用。此外,通过使用计算属性,您可能会更加轻松。
我不确定您是否可以在 Swift 中开箱即用。我将需要 Swift 尚未很好支持的反思。另外,即使有反射并且你想出了聪明的方法来实现你需要的东西,如果数据很大,它可能会很慢。
要像这样访问它,您需要将字典转换为 Struct,如下所示:
edit/update: Swift 3.x
struct Job: CustomStringConvertible {
let number: Int
let name, client: String
init(dictionary: [String: Any]) {
self.number = dictionary["jobNumber"] as? Int ?? 0
self.name = dictionary["jobName"] as? String ?? ""
self.client = dictionary["client"] as? String ?? ""
}
var description: String {
return "Job#: " + String(number) + " - name: " + name + " - client: " + client
}
}
let dict: [String: Any] = ["jobNumber": 1234,
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"]
let job = Job(dictionary: dict)
print(job.number) // 1234
print(job.name) // "Awards Ceremony"
print(job.client) // "ACME Productions"
print(job) // "Job#: 1234 - name: Awards Ceremony - client: ACME Productions"""
edit/update:
Swift 4 或更高版本 你可以使用 JSON Codable 协议:
struct Job {
let number: Int
let name, client: String
}
extension Job: Codable {
init(dictionary: [String: Any]) throws {
self = try JSONDecoder().decode(Job.self, from: JSONSerialization.data(withJSONObject: dictionary))
}
private enum CodingKeys: String, CodingKey {
case number = "jobNumber", name = "jobName", client
}
}
extension Job: CustomStringConvertible {
var description: String {
return "Job#: " + String(number) + " - name: " + name + " - client: " + client
}
}
let dict: [String: Any] = ["jobNumber": 1234,
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"]
do {
let job = try Job(dictionary: dict)
print(job.number) // 1234
print(job.name) // "Awards Ceremony"
print(job.client) // "ACME Productions"
print(job) // "Job#: 1234 - name: Awards Ceremony - client: ACME Productions\n"
} catch {
print(error)
}
绝对是一个结构的工作。
1. 结构 thread-safe 不需要由 ARC 管理。
2. 一些研究发现,它们的工作速度通常比 类 快大约 30,000 倍。
3. Structs 还提供默认初始化程序,因此您的代码会更清晰。
4、这种情况下,你不用担心inheritance/subclassing.
5. 如果可以的话,面向协议的编程范例建议在 类 上使用结构。
struct Job {
let number: Int
let name: String
let client: String
}
免费初始化器:
let newJob = Job(number: 2, name: "Honey", client: "Jeff")
或者您可以创建一个采用字典的自定义初始化程序:
struct Job {
let number: Int
let name: String
let client: String
init(json: [String: Any]) {
self.number = Int(dictionary["jobNumber"] as? String) ?? 0
self.name = dictionary["jobName"] as? String ?? ""
self.client = dictionary["client"] as? String ?? ""
}
}
用法:
let newJob = Job(json: yourDictionary)
print(newJob.number)
// outputs: 1234
我的两分钱 "logic"。 )关于使用结构等的所有正确...)
不要将数据保存在字典或 JSON 中(就像很多来自网络的那样..),始终将其转换为结构。
效率很高,例如考虑在表视图中排序..
您可以像这样向字典添加扩展以获取通用对象:
extension Dictionary where Key == String, Value: Any {
func object<T: Decodable>() -> T? {
if let data = try? JSONSerialization.data(withJSONObject: self, options: []) {
return try? JSONDecoder().decode(T.self, from: data)
} else {
return nil
}
}
}
并在任何 [String: Any]
词典上像这样使用:
let object: MyDecodableStruct? = dictionary.object()
我正在开发一个本机 iOS 应用程序,该应用程序从我们也可以控制的 Web 服务接收 JSON 格式的数据。计划是在大约 18 个月内更换后端数据库以支持不同的平台。
考虑到这一点,我们希望确保 iOS 应用能够相对容易地适应新的数据源,特别是因为我们可能会更改从服务器通过 JSON.
有两个目标:
为每个 PHP 请求创建一个位置,如果需要可以在其中修改密钥。这将避免挖掘代码以找到诸如
job["jobNumber"]
. 之类的东西
清理我们现有的代码以消除像
job["jobNumber"]
. 这样的引用
我们都是 Swift 的新手,没有 Objective-C 经验,但我认为 Struct 或 Class 适合创建像 job.jobNumber
这样的引用.
应该将字典转换为 class 还是结构?代表采用如下所示的 Dictionary<String, String>
并将其转换为推荐类型的可重用方法的示例代码将非常有帮助。
示例字典:
job = {
"jobNumber" : "1234",
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"
}
想要的结果:
println("job name is \(job.name)")
// prints: job name is Awards Ceremony
我一般都是利用值类来实现你想做的事情。在我的项目中,我做了如下操作:
protocol Request : class {
func toDictionary() -> [String : String]
}
protocol Response : class {
init(dictionary: [String : String])
}
class MyRequest : Request {
var var1: Int
var var2: String
//Other stuff in class...
func toDictionary() -> [String : String] {
//Convert the value to dictionary and return
}
}
class MyResponse : Response {
var var1: String
var var2: Int
//You could have nested object as members
var innerObject: MyInnerResponseClass
//Other stuff in class...
var someCalculatedProperty: String {
return //Calculate property value
}
required init(dictionary: [String : String]) {
//Initialize class from dictionary
}
}
class MyInnerResponseClass: Response {
//Class definition here...
}
对于可用作请求和响应的对象,您可以实现这两种协议。
您只需要编写一次翻译代码,就可以在任何地方轻松使用。此外,通过使用计算属性,您可能会更加轻松。
我不确定您是否可以在 Swift 中开箱即用。我将需要 Swift 尚未很好支持的反思。另外,即使有反射并且你想出了聪明的方法来实现你需要的东西,如果数据很大,它可能会很慢。
要像这样访问它,您需要将字典转换为 Struct,如下所示:
edit/update: Swift 3.x
struct Job: CustomStringConvertible {
let number: Int
let name, client: String
init(dictionary: [String: Any]) {
self.number = dictionary["jobNumber"] as? Int ?? 0
self.name = dictionary["jobName"] as? String ?? ""
self.client = dictionary["client"] as? String ?? ""
}
var description: String {
return "Job#: " + String(number) + " - name: " + name + " - client: " + client
}
}
let dict: [String: Any] = ["jobNumber": 1234,
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"]
let job = Job(dictionary: dict)
print(job.number) // 1234
print(job.name) // "Awards Ceremony"
print(job.client) // "ACME Productions"
print(job) // "Job#: 1234 - name: Awards Ceremony - client: ACME Productions"""
edit/update:
Swift 4 或更高版本 你可以使用 JSON Codable 协议:
struct Job {
let number: Int
let name, client: String
}
extension Job: Codable {
init(dictionary: [String: Any]) throws {
self = try JSONDecoder().decode(Job.self, from: JSONSerialization.data(withJSONObject: dictionary))
}
private enum CodingKeys: String, CodingKey {
case number = "jobNumber", name = "jobName", client
}
}
extension Job: CustomStringConvertible {
var description: String {
return "Job#: " + String(number) + " - name: " + name + " - client: " + client
}
}
let dict: [String: Any] = ["jobNumber": 1234,
"jobName" : "Awards Ceremony",
"client" : "ACME Productions"]
do {
let job = try Job(dictionary: dict)
print(job.number) // 1234
print(job.name) // "Awards Ceremony"
print(job.client) // "ACME Productions"
print(job) // "Job#: 1234 - name: Awards Ceremony - client: ACME Productions\n"
} catch {
print(error)
}
绝对是一个结构的工作。
1. 结构 thread-safe 不需要由 ARC 管理。
2. 一些研究发现,它们的工作速度通常比 类 快大约 30,000 倍。
3. Structs 还提供默认初始化程序,因此您的代码会更清晰。
4、这种情况下,你不用担心inheritance/subclassing.
5. 如果可以的话,面向协议的编程范例建议在 类 上使用结构。
struct Job {
let number: Int
let name: String
let client: String
}
免费初始化器:
let newJob = Job(number: 2, name: "Honey", client: "Jeff")
或者您可以创建一个采用字典的自定义初始化程序:
struct Job {
let number: Int
let name: String
let client: String
init(json: [String: Any]) {
self.number = Int(dictionary["jobNumber"] as? String) ?? 0
self.name = dictionary["jobName"] as? String ?? ""
self.client = dictionary["client"] as? String ?? ""
}
}
用法:
let newJob = Job(json: yourDictionary)
print(newJob.number)
// outputs: 1234
我的两分钱 "logic"。 )关于使用结构等的所有正确...)
不要将数据保存在字典或 JSON 中(就像很多来自网络的那样..),始终将其转换为结构。
效率很高,例如考虑在表视图中排序..
您可以像这样向字典添加扩展以获取通用对象:
extension Dictionary where Key == String, Value: Any {
func object<T: Decodable>() -> T? {
if let data = try? JSONSerialization.data(withJSONObject: self, options: []) {
return try? JSONDecoder().decode(T.self, from: data)
} else {
return nil
}
}
}
并在任何 [String: Any]
词典上像这样使用:
let object: MyDecodableStruct? = dictionary.object()