在Swift中,字典应该转换为类还是结构体?

cnwbcb6i  于 11个月前  发布在  Swift
关注(0)|答案(5)|浏览(96)

我正在开发一个本地iOS应用程序,该应用程序从一个我们也控制的Web服务接收JSON格式的数据。计划在大约18个月内更换后端数据库,以支持不同的平台。
考虑到这一点,我们希望确保iOS应用程序能够相对容易地适应新的数据源,特别是在我们可能会更改通过JSON从服务器接收的关联数组中使用的键时。
有两个目标:
1.为每个PHP请求创建一个单独的位置,如果需要的话,可以在那里修改键。这样可以避免在代码中寻找job["jobNumber"]之类的东西。
1.清理我们现有的代码,同时删除job["jobNumber"]之类的引用。
我们都是Swift的新手,没有Objective-C的经验,但我认为Struct或Class适合创建像job.jobNumber这样的引用。
字典是否应该转换为类或结构?示例代码表示一个可重用的方法,该方法如下所示获取Dictionary<String, String>,并将其转换为推荐的类型,这将非常有用。

字典示例:

job = {
    "jobNumber" : "1234",
    "jobName" : "Awards Ceremony",
    "client" : "ACME Productions"
}

字符串

所需结果:

println("job name is \(job.name)")
// prints: job name is Awards Ceremony

mrwjdhj3

mrwjdhj31#

要像这样访问它,您需要将字典转换为Struct,如下所示:
编辑/更新: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
    }
}

个字符
编辑/更新:

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)
}

的字符串

yhived7q

yhived7q2#

绝对是一个结构的工作。

1.结构是线程安全的,不需要ARC管理。
2.一些研究发现,它们的工作速度比一般的类快30,000倍。
3.结构还提供了默认的初始值设定项,这样你的代码会更干净。
4.在这种情况下,你不必担心继承/子类化。
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

1l5u6lss

1l5u6lss3#

你可以像这样为Dictionary添加一个扩展来获取泛型对象:

extension Dictionary where Key == String, Value: Any {

    func object<T: Decodable>() throws -> T {
        let data = try? JSONSerialization.data(withJSONObject: self, options: []) 
        return try JSONDecoder().decode(T.self, from: data)
    }
}

字符串
并在任何[String: Any]字典上这样使用:

let object: MyDecodableStruct? = try? dictionary.object()

d4so4syb

d4so4syb4#

我通常使用值类来实现你想要做的事情。在我的项目中,我做了如下事情:

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还没有很好地支持反射。而且即使有反射,你想出了一个聪明的方法来实现你所需要的,如果数据很大,它可能会很慢。

50few1ms

50few1ms5#

我对“逻辑”的两点看法。)关于使用结构等等都是正确的。
不要将数据保存在dict或JSON中(很多web上的数据都是这样做的),总是将其转换为struct。
很多效率,想想例如关于排序在一个tableview..

相关问题