Gestire JSON con un Model Value in Swift

512_boxSe stai sviluppando un app per iOS c’è una buona probabilità che tu stia ricevendo dei dati da un webservice remoto in formato JSON.

A volte il JSON viene passato direttamente al ViewController che lo utilizza per popolare l’interfaccia o per effettuare altre operazioni. Questo è sbagliato perché crea del codice più complesso o più insicuro.

Infatti siccome un JSON è tipicamente rappresentato con un Dictionary (o il corrispondente type se stai usando una libreria esterna), il compilatore non può garantire che un determinato campo del JSON:

  1. esista
  2. sia popolato
  3. contenga un valore del tipo corretto

Questo significa che devi ripetere manualmente questi controlli ogni volta che utilizzi un JSON (codice più complesso) e se non lo fai l’app corri il rischio di avere un crash nel momento in cui il JSON ricevuto non sia corretto (codice più insicuro).

Un esempio concreto

Immaginiamo un JSON contenente una lista di blocchi dove ogni elemento rappresenta uno show televisivo.

512_retro-tv

Uno show deve contenere i seguenti campi

  • name: String
  • firstEpisodeAired: String
  • seasons: Int
  • genres: Array di String
  • web: Url (opzionale)

Ecco un esempio di JSON: notate che il terzo elemento, ovvero Battlestar Galacticanon è valido perché il campo season contiene una stringa invece di un intero.

Model Value

Creiamo ora una struct che rappresenta uno show

Abbiamo aggiunto 5 properties (dichiarate come costanti). La property web inoltre è stata dichiarata Optional in quanto il valore potrebbe non essere presente nel JSON.

Inoltre abbiamo definito un failable initializer che riceve un valore di tipo JSON e, nel caso in cui tutti i dati siano presenti e validi, crea un valore di tipo Show.

Un Model Value così definito ci garantisce che se esiste un valore di tipo Show, allora questo è valido.

Per quanto riguarda il tipo JSON è definito nella libreria opensource SwiftyJSON che ti consiglio di scaricare e iniziare a usare da subito nei tuoi progetti in quanto rappresenta (secondo me) la migliore libreria Swift per la gestione dei JSON.

Utilizzo

Per semplicità ho salvato in Playground un file Data.json contenente il JSON visto in precedenza. Vediamo come leggerlo.

Il costrutto guard si occupa di estrarre un valore di tipo NSData dal file locale.

Successivamente la libreria SwiftyJSON permette di trasformare NSData in un valore di tipo JSON.

Infine nell’ultima istruzione viene estratto un array e ogni elemento dell’array (una porzione del JSON) viene passata al costruttore di Show che tenta di inizializzare un valore di tipo Show.

Il risultato è un array di Show, facciamo una prova.

Il valore shows (tipo [Show]) contiene 2 elementi. Infatti il terzo blocco del JSON è stato scartato perché il campo seasons era popolato con la stringa "NOT A NUMBER". Analogamente sarebbe stato scartato qualsiasi blocco che non produceva un valore Show valido.

A questo punto possiamo trasferire shows ad altri livelli dell’applicazione (come il controller) e utilizzarlo in modo sicuro.

Luca Angeletti

Trainer • Developer • Writer

3 thoughts to “Gestire JSON con un Model Value in Swift”

  1. Luca, è ok, è tra i migliori articoli che io abbia mai letto sul tema, ma:
    1. manca un esempio con caricamento remoto (e va be’) e uso di delegate su VC al caricamento;
    2. non tiene conto del fatto che i JSON che provengono da server possono essere mostri con decine e decine di entries;
    3. non tiene conto del fatto che in una app tu potresti voler richiamare dozzine di endpoint restful che restituiscono oggetti molto diversi tra loro: che si fa, si crea uno struct per ogni tipo di risultato? Io ho una app in cui richiamo 31 diversi endpoint su un server che non controllo, mi creo 31 struct? Mi devo costruire un tool JSON-to-struct, così se li scrive da sé. 🙂 Scherzi a parte, la cosa presume pure una approfondita conoscenza dei JSON che ti arrivano. Ad esempio: se il JSON mi invia dati che non mi servono, posso estrometterli dallo struct? Posso, ma è buona pratica?

    1. Ciao Gabriele,

      ti ringrazio per le tue osservazioni. Ecco le mie risposte.

      1. hai ragione 🙂
      2. se i JSON sono particolarmente complessi (ad esempio hanno più livelli) puoi replicare il meccanismo descritto in questo post per gestire i livelli successivi. Ottima osservazione: scriverò un articolo in merito
      3. se devi gestire molti JSON il mio consiglio è di usare sempre il meccanismo descritto qui, ovvero creare un model e trasformare il JSON in un model value appena lo ricevi. L’alternativa è quella di usare i JSON direttamente dentro l’app ma è un strada molto rischiosa.
      Infine se sai che una parte del JSON non è necessaria per la tua app puoi tranquillamente omettere quella parte del model e ignorare quei dati.

      Ultima osservazione, con Swift 4 la gestione del JSON diventa estremamente più semplice grazie al protocollo Codable. Praticamene non devi più scrivere l’init a mano come mostrato in questo articolo.

      1. Sì, in teoria (rispetto alla risposta 3) tu potresti addirittura avere n model a partire dal JSON scaricato da una unica request, semplicemente perché alle volte gli endpoint che ti vai a richiamare (che possono essere vari in una app) possono restituirti dati condivisi tra le request. Grazie per la risposta, e continua così 🙂

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *