2015-08-12 31 views
21

Sono relativamente nuovo alla programmazione iOS. Tuttavia, avrei assunto che Swift avrebbe un modo automatico di convertire oggetti in JSON e viceversa. Detto questo, ho trovato diverse librerie che possono farlo.Come convertire un oggetto Swift in un dizionario

TUTTAVIA ...

Sembra che non importa quanto si registra i dati a un servizio Web (anche usando qualcosa come AlamoFire), le richieste deve essere un dizionario. Tutti questi forum mostrano esempi di quanto sia facile convertire la stringa JSON restituita in oggetti. Vero. Ma la richiesta deve essere codificata manualmente. Ovvero, passa attraverso tutte le proprietà dell'oggetto e le mappa come un dizionario.

Quindi la mia domanda è questa: mi manca qualcosa? Ho sbagliato tutto e c'è un modo super facile per (a) inviare JSON (invece di un dizionario) nella RICHIESTA o (b) convertire automaticamente un oggetto in un dizionario?

Ancora una volta, vedo quanto sia facile gestire una risposta JSON. Sto solo cercando un modo automatico per convertire l'oggetto richiesta che voglio postare su un servizio web in un formato che richiede una libreria come AlamoFire (o qualsiasi altra cosa). Con altri linguaggi questo è abbastanza banale, quindi spero che ci sia un modo altrettanto semplice e automatico con Swift.

risposta

4

Attualmente Swift non supporta la riflessione avanzata come Java o C#, quindi la risposta è: no, non esiste un modo altrettanto semplice e automatico con puro Swift.

[Aggiorna] Swift 4 ha nel frattempo il protocollo Codable che consente la serializzazione su/da JSON e PLIST.

typealias Codable = Decodable & Encodable 
+0

in effetti la riflessione non è avanzata come in altre lingue, ma ci sono ancora alcuni modi per ottenere ciò, vedere [la mia risposta] (http://stackoverflow.com/questions/31971256/how-to-convert-a-swift- object-to-a-dictionary/32682463 # 32682463) – fencingCode

+1

Ho scritto la risposta in tempi di Swift 1.2. – Darko

40

Non sono d'accordo con @Darko.

In Swift 2,

uso protocollo di programmazione orientata e la riflessione semplice offerto da Specchio classe:

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

quindi è possibile utilizzare questo protocollo con la classe richiesta e produrre il dizionario desiderato:

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

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

child.value è di tipo Any, si perdono le informazioni sul tipo.Quindi, come riflettere un albero degli oggetti profondo con altri oggetti, array, dizionari, ecc.? – Darko

+2

come è documentato? vedere [API Apple] (https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Mirror_Structure/index.html#//apple_ref/swift/tdef/s:VSs6Mirror5Child) – fencingCode

+2

Apple Swift Riferimento alla libreria standard: ['Mirror Structure Reference'] (https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Mirror_Structure/index.html) ... questo è un link di rilascio al posto del link precedentemente commentato ".../prerelease/ios/...". –

2

È inoltre possibile utilizzare la libreria ObjectMapper. Ha un metodo "toJSON" che converte il tuo oggetto in un dizionario.

3

Senza usare la riflessione, e lavora per gli oggetti nidificati (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 
    } 
} 

Basta implementare le proprietà e valueForKey per il costume gli oggetti che si desidera convertire. Ad esempio:

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

Se necessario, è possibile aggiungere più tipi di valori nella funzione toDictionary.

+0

Questa risposta non sarà più veloce rispetto all'utilizzo di Mirror? Per me va bene – pwcremin

Problemi correlati