Aplicațiile IOS au permanentă nevoie de comunicare peste rețea, fie către un server local sau internet.
Dacă până la SWIFT 4 lucrurile erau pre puțin standardizate, surpiza făcută de Apple este pe măsura așteptărilor.
Să începem discuția.
O aplicație IOS va trimite peste rețea date în format binar sau text. Pentru a realiza acest lucru are nevoie de convertirea instanțelor din aplicația locală într-un format diferit care este acceptat de mașina destinație. Acest proces de conversie a informațiilor locale în format inteligibil de către un server se numește SERIALIZARE. Apple propune un mecanism de encoding pentru a realiza această conversie și un mecanism invers de conversie a răspunsului venit de la server în informație inteligibilă în aplicație, numit decoding.
Protocoale necesare: Encodable & Decodable & Codable
Pentru a conforma o clasă la Codable trebuie ca toate proprietățile sale să fie în prealabil Codable.
Tipurile standard: Float, Int, String, Data, Date, URL sunt conforme cu Codable, prin urmare structura următoare este explicit Codable, suportând metodele init(from:) și encode(to:).
struct Pescar:Codable { var nume: String var numarPermis: Int }
Trebuie să specificăm faptul că tipurile Array, Dictionary sau Optional sunt Codable dacă ele conțin tipuri de date Codable.
Un mic exemplu în acest sens:
let pescarIncepator = Pescar(nume: "Danut", numarPermis: 1) let jsonEncoder = JSONEncoder() let jsonData = try jsonEncoder.encode(pescarIncepator) print("JSON venit din Codable: /(jsonData)") // JSON venit din Codable: 10 bytes
jsonData reprezintă formatul binar pe care-l va primi serverul și pe care-l va transforma ulterior în JSON-ul așteptat.
Dacă încercăm să afișăm conținutul jsonData vom obține de fapt doar o dimensiune a binarului care conține JSON-ul.
“Miezul” jsonData-ului poate fi afișat sub forma:
let jsonString = String(data: jsonData, encoding: .utf8) print("JSON venit din Codable: /(jsonString)") // JSON venit din Codable: {"nume":"Danut","numarPermis":1}
Raspunsul serverului trebuie decodificat pe cale inversă, folosind decode(_:from:)
let jsonDecoder = JSONDecoder() let pescarAvansat = try jsonDecoder.decode(Pescar.self, from: jsonDataResponse) // JSON venit din Codable: {"nume":"Dorulet","numarPermis":2}
Observații
1.jsonDataResponse este raspunsul furnizat de server ca urmare a unui request furnizat anterior.
2. decoder-ul are nevoie să cunoască spre ce tip va converti JSON-ul prin jsonDataResponse
Situație critică – în backend s-a modificat structura tabelei asociată pescarilor noștri astfel încât în acest moment câmpul numarPermis a fost redenumit în idPermis. Cum se poate gestiona o astfel de situație?
Swift 4 vine cu un protocol nou CodingKey și cu un enumeration special CodingKeys.
Ce avem de făcut astfel încât să serializăm instanța noastră de tip Pescar pentru ca pe server JSON-ul să conțină idPermis?
Vom modela un pic struct-ul nostru:
struct Pescar:Codable { var nume: String var numarPermis: Int enum CodingKeys: String, CodingKey { case nume case numarPermis = "idPermis" } }
Prin urmare,
let pescarIncepator = Pescar(nume: "Danut", numarPermis: 1) let jsonEncoder = JSONEncoder() let jsonData = try jsonEncoder.encode(pescarIncepator) let jsonString = String(data: jsonData, encoding: .utf8) print("JSON venit din Codable: /(jsonString)") // JSON venit din Codable: {"nume":"Danut","idPermis":1}