Can Swift convert a class / struct data into dictionary?

前端 未结 3 1159
梦如初夏
梦如初夏 2020-11-30 03:41

For example:

class Test {
    var name: String;
    var age: Int;
    var height: Double;
    func convertToDict() -> [String: AnyObject] { ..... }
}

let         


        
相关标签:
3条回答
  • 2020-11-30 03:48

    You can just add a computed property to your struct to return a Dictionary with your values. Note that Swift native dictionary type doesn't have any method called value(forKey:). You would need to cast your Dictionary to NSDictionary:

    struct Test {
        let name: String
        let age: Int
        let height: Double
        var dictionary: [String: Any] {
            return ["name": name,
                    "age": age,
                    "height": height]
        }
        var nsDictionary: NSDictionary {
            return dictionary as NSDictionary
        }
    }
    

    You can also extend Encodable protocol as suggested at the linked answer posted by @ColGraff to make it universal to all Encodable structs:

    struct JSON {
        static let encoder = JSONEncoder()
    }
    extension Encodable {
        subscript(key: String) -> Any? {
            return dictionary[key]
        }
        var dictionary: [String: Any] {
            return (try? JSONSerialization.jsonObject(with: JSON.encoder.encode(self))) as? [String: Any] ?? [:]
        }
    }
    

    struct Test: Codable {
        let name: String
        let age: Int
        let height: Double
    }
    
    let test = Test(name: "Alex", age: 30, height: 170)
    test["name"]    // Alex
    test["age"]     // 30
    test["height"]  // 170
    
    0 讨论(0)
  • 2020-11-30 03:57

    A bit late to the party, but I think this is great opportunity for JSONEncoder and JSONSerialization. The accepted answer does touch on this, this solution saves us calling JSONSerialization every time we access a key, but same idea!

    extension Encodable {
    
        /// Encode into JSON and return `Data`
        func jsonData() throws -> Data {
            let encoder = JSONEncoder()
            encoder.outputFormatting = .prettyPrinted
            encoder.dateEncodingStrategy = .iso8601
            return try encoder.encode(self)
        }
    }
    

    You can then use JSONSerialization to create a Dictionary if the Encodable should be represented as an object in JSON (e.g. Swift Array would be a JSON array)

    Here's an example:

    struct Car: Encodable {
        var name: String
        var numberOfDoors: Int
        var cost: Double
        var isCompanyCar: Bool
        var datePurchased: Date
        var ownerName: String? // Optional
    }
    
    let car = Car(
        name: "Mazda 2",
        numberOfDoors: 5,
        cost: 1234.56,
        isCompanyCar: true,
        datePurchased: Date(),
        ownerName: nil
    )
    
    let jsonData = try car.jsonData()
    
    // To get dictionary from `Data`
    let json = try JSONSerialization.jsonObject(with: jsonData, options: [])
    guard let dictionary = json as? [String : Any] else {
        return
    }
    
    // Use dictionary
    
    guard let jsonString = String(data: jsonData, encoding: .utf8) else {
        return
    }
    
    // Print jsonString
    print(jsonString)
    

    Output:

    {
      "numberOfDoors" : 5,
      "datePurchased" : "2020-03-04T16:04:13Z",
      "name" : "Mazda 2",
      "cost" : 1234.5599999999999,
      "isCompanyCar" : true
    }
    
    0 讨论(0)
  • 2020-11-30 04:00

    You could use Reflection and Mirror like this to make it more dynamic and ensure you do not forget a property.

    struct Person {
      var name:String
      var position:Int
      var good : Bool
      var car : String
    
      var asDictionary : [String:Any] {
        let mirror = Mirror(reflecting: self)
        let dict = Dictionary(uniqueKeysWithValues: mirror.children.lazy.map({ (label:String?, value:Any) -> (String, Any)? in
          guard let label = label else { return nil }
          return (label, value)
        }).compactMap { $0 })
        return dict
      }
    }
    
    
    let p1 = Person(name: "Ryan", position: 2, good : true, car:"Ford")
    print(p1.asDictionary)
    

    ["name": "Ryan", "position": 2, "good": true, "car": "Ford"]

    0 讨论(0)
提交回复
热议问题