web-dev-qa-db-fra.com

Comment convertir un Swift en dictionnaire

Je suis relativement nouveau dans la programmation iOS. Cependant, j'aurais supposé que Swift aurait un moyen automatisé de convertir des objets en JSON et vice versa. Cela étant dit, j'ai trouvé plusieurs bibliothèques qui peuvent le faire.

TOUTEFOIS...

Il semble que peu importe la façon dont vous publiez des données sur un service Web (même en utilisant quelque chose comme AlamoFire), les demandes doivent être un dictionnaire. Tous ces forums montrent des exemples de la facilité avec laquelle il est possible de convertir la chaîne JSON retournée en objets. Vrai. Mais la demande doit être codée manuellement. Autrement dit, parcourez toutes les propriétés de l'objet et mappez-les en tant que dictionnaire.

Ma question est donc la suivante: ai-je raté quelque chose? Ai-je tout faux et il existe un moyen super simple soit (a) d'envoyer du JSON (au lieu d'un dictionnaire) dans la DEMANDE ou (b) de convertir un objet automatiquement en un dictionnaire?

Encore une fois, je vois à quel point il est facile de traiter une réponse JSON. Je cherche juste un moyen automatique de convertir l'objet de requête que je veux publier sur un service Web dans un format requis par une bibliothèque comme AlamoFire (ou autre). Avec d'autres langues, c'est assez trivial, donc j'espère qu'il y a un moyen tout aussi simple et automatisé avec Swift.

30
JL Gradley

Swift ne prend actuellement pas en charge la réflexion avancée comme Java ou C # donc la réponse est: non, il n'y a pas de méthode aussi simple et automatisée avec Swift pur.

[Update] Swift 4 a quant à lui le protocole Codable qui permet de sérialiser vers/depuis JSON et PLIST.

typealias Codable = Decodable & Encodable
8
Darko

Je dois être en désaccord avec @Darko.

Dans Swift 2,

utiliser programmation orientée protocole et la réflexion simple offerte par Mirror class:

protocol JSONAble {}

extension JSONAble {
    func toDict() -> [String:Any] {
        var dict = [String:Any]()
        let otherSelf = Mirror(reflecting: self)
        for child in otherSelf.children {
            if let key = child.label {
                dict[key] = child.value
            }
        }
        return dict
    }
}

alors vous pouvez utiliser ce protocole avec votre classe de requête et produire le dictionnaire souhaité:

class JsonRequest : JSONAble {
    var param1 : String?
    // ...
}

let request = JsonRequest()
// set params of the request
let dict = request.toDict()
// use your dict
45
fencingCode

Sans utiliser la réflexion, et fonctionne pour les objets imbriqués (Swift 4):

protocol Serializable {
    var properties:Array<String> { get }
    func valueForKey(key: String) -> Any?
    func toDictionary() -> [String:Any]
}

extension Serializable {
    func toDictionary() -> [String:Any] {
        var dict:[String:Any] = [:]

        for prop in self.properties {
            if let val = self.valueForKey(key: prop) as? String {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Int {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Double {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Array<String> {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Serializable {
                dict[prop] = val.toDictionary()
            } else if let val = self.valueForKey(key: prop) as? Array<Serializable> {
                var arr = Array<[String:Any]>()

                for item in (val as Array<Serializable>) {
                    arr.append(item.toDictionary())
                }

                dict[prop] = arr
            }
        }

        return dict
    }
}

Implémentez simplement les propriétés et valueForKey pour les objets personnalisés que vous souhaitez convertir. Par exemple:

class Question {
    let title:String
    let answer:Int

    init(title:String, answer:Int) {
        self.title = title
        self.answer = answer
    }
}
extension Question : Serializable {
    var properties: Array<String> {
        return ["title", "answer"]
    }

    func valueForKey(key: String) -> Any? {
        switch key {
        case "title":
            return title
        case "answer":
            return answer
        default:
            return nil
        }
    }
} 

Vous pouvez ajouter plus de types de valeur dans la fonction toDictionary si vous en avez besoin.

5

Vous pouvez également utiliser la bibliothèque ObjectMapper . Il a une méthode "toJSON" qui convertit votre objet en dictionnaire.

3
Remy Cilia