簡體   English   中英

應該將字典轉換為 Swift 中的類或結構嗎?

[英]Should a dictionary be converted to a class or struct in Swift?

我正在開發一個本地 iOS 應用程序,該應用程序從我們也控制的 Web 服務接收 JSON 格式的數據。 計划是在大約 18 個月內更換后端數據庫以支持不同的平台。

考慮到這一點,我們希望確保 iOS 應用程序將相對容易適應新的數據源,特別是因為我們可能會更改通過 JSON 從服務器接收的關聯數組中使用的鍵。

有兩個目標:

  1. 為每個 PHP 請求創建一個位置,如果需要,可以在其中修改密鑰。 這將避免挖掘代碼以查找諸如job["jobNumber"]

  2. 清理我們現有的代碼以消除像job["jobNumber"]這樣的引用。

我們都是 Swift 新手,沒有 Objective-C 經驗,但我認為 Struct 或 Class 適合創建像job.jobNumber這樣的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

要像這樣訪問它,您需要將字典轉換為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
    }
}

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"""

編輯/更新:

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

我通常使用價值類來實現你想要做的事情。 在我的項目中,我做了類似以下的事情:

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尚未得到很好支持的反思。 即使有反射並且你想出了一個聰明的方法來實現你需要的東西,如果數據非常大,它可能會非常慢。

絕對是結構的工作。 結構是線程安全的,不需要由ARC管理。 一些研究發現,與一般課程相比,它們的工作速度要快30,000倍。 結構還提供默認初始值設定項,因此您的代碼將更清晰。 同樣在這種情況下,您不必擔心繼承/子類化。 您很可能也不希望將字典視為引用類型。 如果你能夠,面向協議編程范例建議在類上使用結構。

struct Job {
    let jobNumber: Int
    let jobName: String
    let client: String
}

關於“邏輯”我的兩分錢。 )所有關於使用結構等的正確...)

不要在dict或JSON中保留(盡可能多的來自web do ..)數據,始終將其轉換為struct。

很多有效的,想想例如關於在tableview中排序..

您可以像這樣向 Dictionary 添加擴展以獲取通用對象:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM