Compatibile con Xcode 9

Il database Realtime di Firebase con il linguaggio Swift

ENTRA NEL NOSTRO GRUPPO FACEBOOK

Come si dice dalle mie parti, perché reinventare la ruota quando già qualcuno ha fatto il lavoro sporco per te?

Uno dei più grandi problemi di chi lavora singolarmente, o con una cerchia ristretta di sviluppatori, è la difficoltà di trattare e maneggiare tecnologie differenti per la realizzazione della propria applicazione.

A cosa mi riferisco?

Ormai le applicazioni sono tutte connesse alla rete. Tutte hanno le notifiche Push Online, tutte utilizzano un sistema di login personalizzato o tramite social e tutte hanno uno storage sul Cloud. In pratica, tutte le applicazioni sono sulle nuvole.

Ed è proprio questo il problema di cui parlavo. La mole di tecnologia e servizi, che utilizzano linguaggi e sistemi differenti rispetto al nostro amato linguaggio Swift, bloccano sul nascere le aspettative della maggior parte dei sviluppatori indipendenti.

Ma la storia ci insegna che dove c’è un problema c’è anche una soluzione.

La soluzione che io sto adottando per le mie applicazioni iOS si chiama Firebase. Ed In questo tutorial voglio darti tutti gli strumenti per utilizzare il database realtime di Firebase con il linguaggio Swift.

Firebase ios linguaggio swift

Cos’è Firebase?

Firebase è un SaaS (Software as a Service) online gratuito, acquistato da Google, che imbriglia dentro di se tutto il necessario per poter realizzare un’applicazione connessa al Cloud (con tutti i servizi che elencavo sopra) in maniera semplificata ed intuitiva.

Per semplificata intendo che non dovrai imparare nessun nuovo linguaggio di programmazione, non dovrai configurare server, connessioni e cosa più importante è gratuito (fino ad una certa soglia) e scalabile su tutte le piattaforme in circolazione (potrai utilizzare lo stesso Database di Firebase anche per progetti Android e Web).

Firebase ormai è una realtà più che consolidata e famosa, tanto da aver convinto Skyscanner e Shazam ad utilizzarlo come sistema di cloud storage.

Ti ho detto che Firebase è un servizio online. Per adesso te lo spiego così, poi vedremo nel dettaglio di che si tratta e cosa c’è realmente sotto la scocca.

Ma in pratica, a che serve Firebase e perché è importante per creare un’applicazione?

Ipotizziamo che la tua applicazione abbia bisogno di un Database Online. Ovvero hai bisogno di un posto online dove poter memorizzare le informazioni per poterle pescare dai tuoi dispositivi (come quello che hai utilizzato in locale con il Core Data) o perché, magari, questi dati devono essere letti ed interpretati dagli altri utenti della tua applicazione.

Senza Firebase, quello che avresti fatto sarebbe stato comprare uno spazio da un Host online, creare un Database SQL o NoSQL (vedi sotto) scrivere un sistema con un linguaggio Web (tipo PHP o Java) per poi interfacciare la tua applicazione iOS con quel sistema. Una procedura noiosa, lunga e complicata se non si conosce il funzionamento del web ed i suoi linguaggi.

Con Firebase ti basterà letteralmente e praticamente premere un bottone per creare uno spazio online che, grazie ad un framework progettato per il linguaggio Swift, potrai modificare e modellare direttamente dalla tua applicazione o da un’interfaccia Web intuitiva che ti mette a disposizione la stessa Firebase.

La caratteristica più di spicco di Firebase è la sua tecnologia Real Time (non mi piace parlare di Real Time però il termine rende bene l’idea).

I dati che scriverai nel database saranno immediatamente disponibili a tutti gli utenti connessi a quello spazio. Questa sua caratteristica è quella che ti potrebbe portare a realizzare una semplice chat online per la tua applicazione (ne parlerò in un tutorial separato).

Non voglio dilungarmi troppo nelle presentazioni di Firebase. Ti elenco le caratteristiche principali per poi cominciare a vedere come poter utilizzare il database Realtime di Firebase con il linguaggio Swift:

  • Realtime Database: I tuoi dati saranno accessibili ovunque ed in maniera istantanea. Es. scrivo un messaggio, lo salvo su Firebase e quel messaggio viene subito letto da un’altra applicazione.
    •  Firestore Database: Un evoluzione del Realtime Database, a discapito di un po’ di velocità, ha un’organizzazione migliore dei dati e delle query di ricerca più evolute.
  • Autenticazione: Puoi creare un tuo sistema di autenticazione (per esempio con email e password) oppure puoi utilizzare quelli dei Social in maniera semplificata.
  • Storage: Puoi archiviare su Firebase qualsiasi tipologia di dati. Dalle immagini, ai PDF ai normali tipi di dato come le stringhe e i numeri.
  • AdMob: Con Firebase accedi anche al framework AdMob che ti permette di monetizzare la tua applicazione tramite l’advertising (i banner).
  • Analytics: Ti mette a disposizione la potenza di Google Analytics per le statistiche della tua applicazione.
  • Altro: Vedi l’immagine sotto.

unnamed

In questa introduzione al database Realtime di Firebase con il linguaggio Swift voglio farti prendere confidenza con il sistema dei Database Realtime, analizzando ogni singolo componente del framework Firebase Database

Pronto per cominciare?

Allora vediamo insieme come utilizzare il database Realtime di Firebase con il linguaggio Swift!

Registrazione e creazione app Firebase

Il primo step che devi fare è quello di registrarti a firebase.google.com. Grazie al tuo account Google potrai entrare direttamente senza dover passare per la registrazione. In alto a destra troverai il bottone Accedi.

firebase creare applicazione ios xcode swift

Una volta fatto l’accesso, potrai entrare all’interno della Console di firebase per poter gestire i tuoi progetti.

Puoi entrare all’interno della console utilizzando anche questo link: console.firebase.google.com.

All’interno, se non hai mai utilizzato Firebase, troverai un enorme bottone con scritto Create New Project o Aggiungi Progetto. Premilo e successivamente ti chiederà di assegnare un nome al progetto e lo stato della tua residenza o società.

Il nome può essere indipendente dal nome che poi darai effettivamente alla tua applicazione iOS. Io ti consiglio di mettere nomi simili in modo da ricordarti che quel progetto Firebase è associato a quella determinata App dato che potrai avere N progetti su Firebase.

firebase-console-creazione-di-un-progetto-per-app-database

Questo progetto rappresenterà il ponte di congiunzione tra le tue applicazioni (sia iOS, Android che Web) e l’ecosistema di Firebase.

In pratica, utilizzerai questo progetto Firebase come contenitore e gestore delle informazioni delle tue applicazioni che vorranno utilizzare Firebase come sistema di cloud database (o le altre funzionalità).

Interfaccia Firebase

L’interfaccia della web app di Firebase è abbastanza intuitiva. Nel menu di destra puoi interagire con le varie componenti e feature di Firebase. Di default sono tutte disponibile e, ovviamente, verranno attivate solamente quando la tua applicazione ne avrà bisogno.

Questa suddivisione dei servizi ti permette di sfruttare solamente ciò che è necessario ai fini della tua applicazione. Per esempio, se la tua applicazione ha bisogno di utilizzare il login con Facebook o un login classico (email e password) potrai interagire solamente con la parte di autenticazione che è contenuto all’interno del pannello Auth.

Ogni caratteristica verrà trattata a suo tempo. In questo tutorial passeremo a rassegna solamente la parte di Database contenuta nell’omonimo pannello.

Collegare Firebase alla propria applicazione iOS

La prima cosa che devi fare, non appena crei un progetto su Firebase, è collegarlo ad una tua applicazione. Firebase ti permette di collegare lo stesso progetto Firebase a più applicazioni (Android, iOS e Web).

Dato che noi ci stiamo occupando di iOS. Imboccheremo questa strada.

creare-applicazione-firebase-ios-swift-xcode

Registrare l’App

Prima di procedere, crea una nuova applicazione come nuovo progetto Single View Application iOS.

Poi torna su Firebase. Nel primo step ti vengono richieste alcune informazioni dell’applicazione.

  • ID Bundle iOS: Quello che noi chiamiamo Bundle Identifier cioè l’identificatore univoco della tua applicazione. Questo Bundle ID lo generi in fase di creazione del progetto e puoi modificarlo o vederlo all’interno delle impostazioni del progetto e precisamente sul pannello General della tua app su Xcode.
    Questo campo è obbligatorio e deve essere obbligatoriamente uguale al Bundle Identifier che possiede la tua applicazione (nuova o esistente che sia).
  • App Store ID: Il tuo identificatore all’interno dell’App Store. Lo puoi trovare nell’URL della tua applicazione all’interno dell’App Store. Esempio, il numero alla fine dell’URL è il tuo App Store ID https://itunes.apple.com/us/app/yourapp/id123456789.
    Questo campo è facoltativo.

Per sicurezza, se hai creato un progetto o hai il progetto che vuoi collegare a Firebase. Questi sono i passaggi da fare per trovare il tuo Bundle ID:

Collegare app ios a firebase

Se tutto va per il verso giusto, alla pressione del tasto Registra App dovrebbe mandarti al secondo step di configurazione.

File di configurazione Xcode

Nel secondo step dovrai scaricare un file di configurazione che dovra inserire dentro Xcode:

Firebase file configurazione Xcode

Questo file, chiamato di default GoogleService-Info.plist contiene tutte le informazioni che serviranno alla tua applicazione per connettersi correttamente a tutti i servizi di Firebase ed al progetto che hai creato.

Una volta scaricato, devi passare questo file all’interno del tuo progetto Xcode. Ti basta trascinarlo all’interno del Target principale (la cartella dove ci sono tutti gli altri file) e selezionare la spunta Copy Item if Needed quando passerai il file (Questo creerà una copia del file all’interno della cartella del tuo progetto Xcode):

file configurazione firebase xcode ios linguaggio swift

Aggiungere gli SDK Firebase (CocoaPods)

Alla tua applicazione manca ancora il framework (un raggruppamento di classi) per poter effettivamente utilizzare Firebase.

Firebase utilizza CocoaPods per semplificare l’aggiunta dei suoi framework ad un progetto iOS. Se non sai cos’è CocoaPods e come utilizzarlo nella tua app, vai immediatamente a guardare questo tutorial di Mauro per metterti in pari con il mio tutorial. CocoaPods potrebbe cambiarti letteralmente l’esistenza!

Hai già installato CocoaPods?

Bene! Adesso apri il terminale e fai un piccolo check sulla versione del tuo CocoaPods scrivendo “pod –version“. Se la tua versione di CocoaPods installata è inferiore alla 1.3 ti esorto a fare l’upgrade se no non potrai proseguire con il tutorial. Per aggiornare CocoaPods ti basta scrivere “sudo gem install cocoapods” (con il sudo, dovrai scrivere la password subito dopo l’invio del comando).

Se hai avuto qualche problema, scrivimi un commento in fondo al tutorial.

Installare i Pod di Firebase

Il progetto della mia applicazione di prova si trova sul Desktop. Con il tuo terminale, muovi l’inspector all’interno del tuo progetto scrivendo il comando “cd IlPercorsoDelTuoProgetto/NomeTuoProgettoXcode“. Nel mio caso sarà:

A questo punto, puoi inizializzare CocoaPods all’interno del tuo progetto per prepararlo a ricevere i framework. Adesso scrivi:

Questo processo creerà un file chiamato PodFile che conterrà le informazioni sui Framework da installare.

installare pod firebase xcode ios

Entra dentro la cartella del tuo progetto, apri il file PodFile e sostituisci il contenuto con il seguente:

Nel tuo PodFile, se hai incollato il mio codice, assicurati di cambiare il nome del target. Nel mio caso il progetto si chiama FirebaseAppTest, quindi scriverò “target ‘FirebaseAppTest’ do“.

I due pod fondamentali all’utilizzo di Firebase e del suo Database Realtime sono:

  1. Firebase/Core: deve sempre esserci in qualsiasi progetto che utilizza Firebase
  2. Firebase/Database: farà in modo che cocoa pods installi l’sdk per il database

L’ultimo passaggio nella console è quello, dopo aver salvato il PodFile modificato, di installare i pod scrivendo:

cocoa pods e firebase xcode ios swift

Da ora in poi dovrai aprire il tuo progetto Xcode utilizzando il file con estensione .xcworskspace. Se già avevi aperto Xcode con il progetto, chiudilo e riaprilo passando da questo nuovo file. Se ti piace scrivere dalla console puoi aprirlo scrivendo “open nomeTuoProgetto.xcworskspace“.

Aprendo il progetto dal file xcworkspace dovresti avere una struttura dei file simile a questa:

struttura progetto xcode con firebase ios

Se dovessi aver avuto qualche problema di qualsiasi sorta, dato che questa è la parte più incasinata del processo di collegamento tra Firebase e l’applicazione iOS, ti prego di comunicarmelo così da poterlo sistemare insieme.

Nell’ultimo passaggio di Firebase, quello che ti chiede di inserirei il codice nell’app, vai pure avanti senza problemi. Lo vedremo insieme più sotto.

Tipologie di Database

Un database è un contenitore di informazioni. Pensalo come ad una libreria, dove ci sono tanti scaffali divisi con qualche particolare logica, per esempio per autore, e dove dentro ad ogni scaffale ci sono le informazioni salvate (nel caso della libreria, sarebbero i libri).

Chi va in libreria ad affittare o comprare un libro non interessa come questo Database sia organizzato e composto. Vuole semplicemente prendere il libro in questione e andarsene. Ed infatti, dentro ad una Libreria c’è sempre un commesso che penserà a recuperare il libro dato che conosce la struttura della libreria.

I database dell’informatica sono simili a delle librerie.

Sono software specializzati nella memorizzazione dei dati in maniera persistente (cioè che non scompaiono quando chiudiamo l’app o spegniamo il computer/server).

Come esistono librerie che organizzano i libri in maniera differente, esistono anche Database che salvano in memoria i dati in maniera completamente differente.

Esistono due tipologie di database o almeno queste sono quelle più utilizzate:

Database SQL

I Database che si dicono relazionali, organizzano le informazioni in una sorta di tabella divisa per righe e colonne. Dove ogni colonna contiene una particolare informazione.

Per esempio una tabella di un database relazione potrebbe essere Utente. Dentro Utente le colonne dividono le informazioni in età, nome, cognome ecc. Nelle righe vengono messi i valori da memorizzare.

La seguente tecnologia è alla base del Core Data (strumento che ti ho fatto utilizzare per la memorizzazione in locale). L’accesso a queste informazioni avviene mediante l’utilizzo dei linguaggi SQL e per tanto vengono chiamati database SQL

Database noSQL

Dall’altro lato esistono i Database non Relazionali. Le informazioni vengono memorizzate, non più in tabelle, ma in strutture di tipo chiave-valore come, più o meno, i dizionari del linguaggio swift.

Questa è la tecnologia che sta alla base dei Database Realtime di Firebase.

Un esempio, poi lo vedremo nel dettaglio, potrebbe essere quello di un dizionario che organizza le informazioni in questo modo:

La chiave dell’informazione è l’username dell’utente, “peppeSap”, associato a questa chiave c’è un dizionario di coppie chiavi valore. Dove le chiavi vengono sempre messe a sinistra e i valori a destra.

La struttura richiama quella della sintassi JSON (il link rimanda ad un tutorial dove, nella prima parte spiego cos’è un file JSON).

Questi Database non relazioni, non utilizzano SQL come metodo di lettura ed interazione e, di conseguenza, vengono chiamati Database NoSQL (Not Only SQL dato che alcuni potrebbero anche utilizzare SQL).

Il Database Realtime di Firebase

Entra dentro il tuo progetto Firebase e spostati nel pannello Database.

Qui ti chiederà di selezionare o il Realtime Database o il Cloud Firestore. Seleziona il Realtime Database.

creare-il-primo-database-realtime-con-firebase

l’area di Realtime Database è divisa in 4 sezioni:

  • Dati: Qui troverai i dati memorizzati all’interno del Database dai tuoi utenti. Tutte le applicazione scriveranno le informazioni qui dentro in una struttura che tra poco analizzerai.
  • Regole: L’accesso ai dati del tuo Database Realtime può essere bloccato o sbloccato in Lettura e Scrittura. Di default, come dice la scritta in azzurrino con la stella, i tuoi utenti devono essere autenticati per poter leggere e scrivere nel database. Noi sbloccheremo questa funzionalità in modo che si possa leggere e scrivere sul Database anche da non autenticati.
  • Backup: Il piano a pagamento di firebase ti permette di eseguire dei backup automatici.
  • Utilizzo: Ti farà vedere quanti accessi simultanei avverranno di giorno in giorno.

interfaccia del database realtime di firebase

La struttura dei Dati

Il database realtime di firebase archivia i dati in strutture simili a file JSON. Un file di tipo JSON come ho già spiegato in questo articolo è simile ad un dizionario del linguaggio swift.

Il punto d’ingresso o la base del database è quel dato che vedi al centro dell’area bianca. Nel mio esempio è:

La chiave del mio database è il nome del mio progetto e, associato a questa chiave, c’è un valore nullo.

Una cosa importante da analizzare è che l’accesso alle informazioni avviene anche mediante gli URL. In alto l’url di default è composto, nel mio esempio, da https://testappxcoding.firebaseio.com/ questo url punta direttamente alla chiave testappxcoding del Database.

I punti d’ingresso del database, che vengono rappresentati dalle chiavi del DB, vengono chiamati Nodi. Quindi, testappxcoding è il primo nodo o Root Node del Database. Da qui potrai accedere a tutti i dati che salveranno gli utenti.

Ovviamente, si può personalizzare il database creando dei sotto nodi. Ogni sotto nodo avrà un URL univoco che sarà dato dalla combinazione dei nodi superiori più il nodo in questione.

Esempio

Ti faccio vedere un esempio abbastanza semplice e poi ti insegnerò a creare delle strutture dati funzionali.

Ipotizziamo che la tua applicazioni, tra le tante cose, permetta di creare un profilo utente condivisibile con gli altri utenti dell’applicazione. L’utente generico si registra all’applicazione creando un nickname ed inserendo dei dati come nome, età e provenienza.

La struttura del tuo Database Realtime dovrà, per tanto, conservare tutti gli utenti suddivisi per nickname. Ma dove vanno inseriti questi utenti?

Se li aggiungessi come sotto nodi del nodo principale rischierei di mischiare, in fasi successive, informazioni diverse tra loro.

Per questo motivo, si può creare un sotto nodo, che serve da contenitore per gli utenti dell’applicazione, chiamato “utenti“. Sotto il nodo “utenti” verranno inseriti degli ulteriori sotto nodi che avranno per chiave il nickname dell’utente registrato.

Quello che verrà fuori è una struttura simile alla seguente:

struttura esempio utenti database realtime firebase

Nell’esempio che vedi sopra, gli utenti vengono archiviati in un sotto nodo chiamato utenti. Dentro “utenti” ci sono due oggetti chiamati “giuseppesapienza” e “lucappalardo” che, oltre ad essere due utenti che si sono registrati alla tua applicazione, sono essi stessi dei sotto nodi.

Il nodo “utenti“, può essere raggiunto utilizzando il link https://testappxcoding.firebaseio.com/utenti/ che ti farà vedere tutti i suoi sotto nodi.

Puoi andare in fondo fino a raggiungere il valore associato ad una chiave. Per esempio, se vuoi leggere il nome dell’utente giuseppesapienza, potrai scrivere https://testappxcoding.firebaseio.com/utenti/giuseppesapienza/nome

Aggiungere dati dalla dashboard

Se sposti il mouse vicino al nodo principale del tuo Database vedrai che comparirà un tasto a forma di più ed un tasto x. Premendo il tasto + puoi aggiungere un nuovo sotto nodo.

Se lo premi vedrai che potrai aggiungere due valori. A sinistra va la chiave ed a destra il valore associato a quella chiave. Nei casi dei nodi che servono da contenitori, come il caso di “utenti“, non è necessario assegnargli un valore.

Però, per poter inserire nodi senza valore, questo deve possedere dei sotto nodi con dei valori. Mi spiego meglio. Se crei il sotto nodo “utenti”, sotto a questo dovrà almeno esserci un sotto nodo riempito con dei valori.

Proviamo a ricreare la struttura che hai visto sopra.

Premi sul tasto + e aggiungi “utenti“. Dato che “utenti” serve da contenitore, premi il tasto + e aggiungi un sotto nodo chiamato “ilTuoUsername” (ipotizziamo che tu ti sia registrato all’app). A questo ulteriore nodo che conterrà i dati dell’utente, premi il tasto + e aggiungi le chiavi “web”, “nome” ed “età” con i rispettivi valori:

esempio inserimento nodi firebase realtime

La modifica e l’eliminazione sono altrettanto semplici. Ti basta passare il mouse sopra un valore da modificare per cambiarlo o sopra la x per eliminarlo. Eliminare un nodo significa eliminare tutti i sotto nodi.

Esercizio 0. Prova ad aggiungere un nuovo utente, con gli stessi attributi.
Esercizio 1. Crea un nuovo nodo principale, chiamato “news” e aggiungigli delle news divise per titolo. Dai come attributi per ogni news il titolo, il luogo ed una descrizione.

Come strutturare correttamente i Dati

Ipotizziamo che un utente della tua applicazione voglia salvare delle note personali associate solamente al suo account. Cioè, l’utente vuole una lista personale di note.

La tentazione più forte, in questi casi, è quella di innestare all’interno dell’utente un nuovo sotto nodo chiamato note. Cosa che crea non pochi problemi:

esempio struttura dati da evitare firebase realtime database

Il problema principale di una struttura del genere è che, quando accederai ad un nodo, per esempio “utenti“, scaricherai tutti i dati e sotto nodi che si troveranno all’interno.

Ora, è vero che il Database Realtime di Firebase permette di innestare i dati fino a 32 livelli di profondità, però, come loro stessi consigliano nella guida ufficiale, è preferibile utilizzare una struttura dei dati Flat.  

Potresti, quindi, optare per un sotto nodo del nodo principale chiamato note dove suddividerai le note degli utenti per username:

struttura flat database realtime firebase

Tra le tantissime proprietà che derivano dall’utilizzare questa struttura c’è indubbiamente sia quella della facilità di lettura (intesa anche come velocità dell’elaborazione) che quella di possedere una struttura di facile manutenzione e upgrade.

Se vuoi dei consigli su come strutturare correttamente i dati del tuo database, scrivi un commento in fondo alla pagina oppure entra nella nostra community Slack o Facebook.

Regole d’accesso

Di default, per poter accedere ai dati del Database realtime di Firebase, i tuoi utenti devono essere autenticati utilizzando uno dei sistemi di Auth di Firebase (email, facebook, twitter ecc).

Dato che in questa guida non stiamo trattando l’autenticazione con Firebase, devi obbligatoriamente sbloccare la lettura e la scrittura dei dati per gli utenti non loggati.

Per farlo, spostati nel pannello Rules del tuo database:

regole utilizzo database realtime firebase

Non voglio addentrarmi molto nelle regole d’accesso al database Realtime, ci ritornerò in un altro articolo, per ora è importante solamente capire che si può modificare l’accesso a qualsiasi nodo del Database.

Di default il blocco rules, così com’è scritto, blocca l’accesso in read e write a tutti gli utenti che non sono autenticati “auth != null“. Per poter rimuovere questo blocco, ti basta cambiare il valore di read e write in true oppure in “auth == null“.

Comparirà un enorme bottone con scritto Pubblica. Cliccalo per confermare la modifica.

Ricordati che, in fase di distribuzione dell’applicazione sull’app store dovrai configurare correttamente le regole d’accesso se non vuoi che qualcuno si inserisca nel tuo Database (dato che può essere letto e modificato da tutti, anche dal web).

Scrivere sul Database di Firebase con linguaggio Swift

Dovresti avere già creato il progetto iOS con il framework di Firebase già importato (con CocoaPods). Adesso è arrivato il momento di vedere come connettere il Database Realtime di Firebase all’app iOS con il linguaggio Swift.

Per prima cosa bisogna inizializzare la connessione con Firebase.

Vai nel tuo AppDelegate, importa il framework Firebase e, dentro il metodo didFinishLaunchingWithOptions, scrivi FirebaseApp.configure():

La classe FirebaseApp rappresenta il punto d’ingresso del framework della connessione con il progetto che hai creato su Firebase.

Il metodo configure() serve a creare la connessione con il progetto. Non hai bisogno di inserire parametri perché il metodo configure() prende le informazioni direttamente dal file GoogleService-info.plist.

Se avvii l’applicazione, in console dovrebbero spuntare dei messaggi. Non preoccuparti del contenuto di questi messaggi. L’importante è che l’app non vada in crash.

Dati possibili

Prima di mettere in piedi un’applicazione, devi imparare ad utilizzare le funzioni di base per il salvataggio dei dati sul database di firebase.

All’interno del Database Realtime puoi salvare diversi tipi di dato tra cui:

  • Stringhe
  • Numeri (Int, Double, Float ecc)
  • Bool
  • Array
  • Dizionari

Database Reference, il punto d’ingresso

Ti ho detto che i dati vengono organizzati in una struttura a nodi dove ogni nodo è raggiungibile da un link univoco. Di conseguenza, per poter scrivere sul Database dall’applicazione è necessario, come prima cosa, definire in quale nodo poter salvare le informazioni.

Il framework di Firebase ha già un oggetto che ti permette di raggiungere il nodo principale dell’applicazione. L’oggetto in questione si chiama Database ed è contenuto all’interno del framework FirebaseDatabase.

Per poter accedere al riferimento del nodo principale, ti basterà utilizzare due metodi sull’oggetto singleton Database. Il primo è database() che restituisce l’istanza del Database ed il secondo, da invocare sul precedente, è reference() che ritorna il link al suddetto nodo.

Adesso spostati nel ViewController. Importa il framework FirebaseDatabase e, nel viewDidLoad, scrivi:

Se avvii l’applicazione, in console, dovresti vedere l’url che punta al nodo principale.

Child, accedere ad un sotto nodo

Se hai seguito gli step precedenti, nel tuo database Firebase dovrebbero esserci due sotto nodi principali. Uno chiamato “utenti” ed uno “note“. Se non li hai, provvedi a crearli.

Per creare un sotto nodo, ricordati che devi obbligatoriamente aggiungere dei dati reali (come per esempio un utente o una nota).

Da codice, per poter accedere ad un sotto nodo puoi utilizzare il metodo child(pathString: String) che restituisce il FIRDatabaseReference (cioè l’url) del sotto nodo passato come parametro. Quindi, se adesso scrivi (sempre nel viewDidLoad):

funzione child accedere a sotto nodo database realtime firebase

Il print del ref_utenti dovrebbe stampare l’url del sotto nodo “utenti“.

Nel caso in cui non esistesse il sotto nodo che stai provando ad accedere, l’app non andrà in crash bensì il Database creerà un sotto nodo temporaneo nell’attesa che, successivamente, gli vengano inseriti dei dati.

Grazie al metodo child ti è possibile navigare all’interno della struttura dei dati. Un altro utilizzo del child è quello di inserire un path più dettagliato. Per esempio, puoi scrivere più path all’interno del child per raggiungere un nodo specifico in un’unica istruzione:

La stessa sintassi può essere scritta così:

SetValue, scrivere e aggiornare un dato

Per poter scrivere sul Database, il primo sistema messo a disposizione è il metodo setValue(value: Any?) che accetta in ingresso un qualsiasi oggetto. Nella pratica accetterà uno dei tipi di dato che ti ho elencato poc’anzi.

Il metodo setValue va invocato su un nodo ben specifico. Per esempio, se volessi aggiungere un nuovo utente, invocherò il setValue sul nodo “utenti“.

Proviamo ad aggiungere un nuovo utente.

Ti ricordo che i il database di Firebase organizza i dati come dei dizionari del linguaggio Swift. Quindi, il nostro nuovo utente, che chiameremo “xcoderA“, avrà come dati il seguente dizionario:

Le chiavi del dizionario corrispondono esattamente alle chiavi che ho dato all’utente che ho creato dal pannello web di firebase. Ovviamente puoi aggiungere qualsiasi tipologia di dato e chiave, gli altri utenti non verranno compromessi. É giusto, però, utilizzare delle chiavi comuni a tutti gli utenti per facilitare la lettura in secondo momento.

Adesso ti basta accedere al child(“utenti”). Su questo poi dovrai creare un sotto nodo con il nome del nuovo utente, ovvero un child(“xcoderA”), ed infine invocare il setValue passandogli il dizionario dati_xcoderA:

Se adesso avvii l’applicazione, vedrai che il Database verrà immediatamente aggiornato con l’aggiunta del nuovo utente e dei suoi relativi dati:

setValue firebase realtime database linguaggio swift ios xcode

La sintassi analoga è la seguente:

A questo punto è facile intuire come un sotto nodo, aggiunto da codice, viene creato solamente quando il setValue assegna un valore a quel nodo. Nel nostro esempio, nel database non era presente il nodo xcoderA, questo è stato aggiunto solo quando il setValue gli ha assegnato il dizionario di valori.

Fai attenzione perché, il setValue, sovrascrive tutto il nodo. Per esempio, se volessi modificare il nome all’utente e scrivessi così:

Questo sovrascriverà tutto il contenuto del nodo “xcoderA” perché gli stai assegnando un nuovo dizionario che contiene solo una coppia di chiave-valore. Ed infatti:

problema-setvalue-su-database-realtime-firebase

Come fare allora?

Per poter risolvere il problema con il setValue, puoi accedere al nodo in questione, cioè il nome dell’utente ed eseguire lì la modifica:

Esercizio 2. Prova ad aggiungere un nuovo utente o una nuova nota utilizzando il setValue. Successivamente modifica uno dei suoi valori.

updateChildValues, aggiornare uno o più nodi

Nel caso volessi modificare un particolare valore associato ad una chiave, senza evitare la sovrascrittura dell’intero nodo o il dover utilizzare il setValue in maniera impropria, puoi utilizzare il metodo updateChildValues(value: Any?).

Questo metodo sovrascrive solo i valori associati a quelle determinate chiavi.

Per esempio, se volessi modificare l’età dell’utente xcoderA, scriverei:

Ma così com’è il metodo non ha un granché di differente rispetto al setValue. Per poter apprezzare la potenza dell’updateChildValues devi immaginarlo applicato a qualcosa di più complesso.

Nella struttura che ho creato ho due sotto nodi, “utenti” e “note“. Ogni utente ha un omonimo nodo che serve a contenere le note salvate. Adesso, pensiamo ad un utilizzo più complesso, ogni utente ha una proprietà che tiene conto del numero di note salvate.

Cioè, avremmo una struttura del genere:

esempio-struttura-database-realtime-firebase-ios-swift

Il nostro utente xcoderA ha una proprietà chiamata n_note che tiene conto del numero di note memorizzate sul database. A questo punto, vogliamo aggiungere una nuova nota e aggiornare anche quel valore.

Grazie all’updateChildValue, invocato sul root, puoi scrivere, come chiave del dizionario passato al parametro, il path da aggiornare e come valore il nuovo dato da aggiungere:

Grazie a questo metodo sei riuscito a fare entrambe le cose contemporaneamente:

esempio-updatechildvalues-firebase-database

Esercizio 3. Prova ad aggiungere un nuovo utente ed una nuova nota utilizzando il metodo updateChildValues.

childByAutoId

Le note dell’utente io le ho numerate utilizzando i numeri decimali, cioè nota-1, nota-2 ecc. Il problema di questa sintassi deriva dal fatto che il database è di tipo realtime e non offre un controllo sulla scrittura simultanea da parte di più utenti sullo stesso nodo.

Mi rispiego.

Ipotizziamo che esista la nota-1. Due utenti stanno provando a scrivere la nota-2 contemporaneamente ma con valori di titolo e descrizione diversi. Quale delle due versioni di nota-2, il database, dovrà accettare?

Questo problema, che sembra banale, apre degli scenari complessi che ricadono in una scienza ben specifica che prende il nome di gestione della concorrenza. É qualcosa di talmente brutto che chi la nomina finisce inesorabilmente per morire di autocombustione.

Fortunatamente ci sono degli eroi, all’interno del team di sviluppo di Firebase, che hanno pensato ad un sistema intelligente per risolvere questo spiacevole problema.

Il metodo childByAutoId crea un sotto nodo univoco che esce fuori dalla combinazione del tempo (inteso come minuti,ora e giorno) e dall’UUID dell’applicazione (cioè un codice univoco assegnato ad ogni applicazione installata dall’utente).

Il fatto che questo AutoId è una funzione del tempo genera dei sotto nodi che vengono automaticamente ordinati cronologicamente. Dunque i nodi saranno organizzati da quello più vecchio al più recente (ordinamento crescente). Utile in moltissime situazioni come news feed e altre tipologie d’applicazioni che operano in funzione del tempo.

Proviamo ad utilizzarlo. Elimina tutte le note presenti sotto xcoderA e, nel tuo viewDidLoad, scrivi:

childbyautoid-firebase-database-realtime

Nel caso in cui volessi utilizzare l’autoId, dato che è univoco per ogni invocazione del metodo, puoi conservarlo in una variabile utilizzando il parametro .key di ogni DatabaseReference.

Ipotizziamo che l’utente, quando crea la nota, la voglia anche salvare tra le sue preferite. Potremmo utilizzare l’autoId generato per salvarlo in un nuovo sotto nodo chiamato “note_preferite”: 

utilizzare-un-autoid-come-chiave-database-realtime-firebase

Leggere dal Database

Leggere dal Database di Firebase è un processo semplice ma con una potenzialità incredibile.

Il sistema che si utilizza per leggere i dati dal Database di Firebase è completamente diverso rispetto al classico sistema: Chiamata -> Elaborazione dal DB -> attesa -> Risposta -> Elaborazione dei dati dall’app.

Con Firebase anche la lettura avviene in realtime.

Tra i metodi di lettura proposti dal framework FirebaseDatabase quello più interessante è l’Observer. Un observer è un oggetto speciale che rimane in attesa dell’aggiornamento di un particolare nodo. L’observer rimane a guardare per un tempo indefinito, un nodo del DB, avvisandoti quando questo viene investito da un evento.

Tutti questi particolari eventi possono essere intercettati dall’Observer in realtime:

  • childAdded: Viene invocato per tutti i sotto nodi esistenti e, successivamente, per ogni nuovo sotto nodo che verrà aggiunto al nodo che si sta osservando.
  • childRemoved: Un sotto nodo viene eliminato.
  • childMoved: Un sotto nodo viene mosso dal nodo osservato.
  • childChanged: Uno sotto nodo viene aggiornato.
  • value: Viene invocato per ogni evento che si verifica sul nodo osservato, compresi i suoi sotto nodi.

Questi eventi vengono descritti dall’enum DataEventType

Per esempio, se l’utente dovesse aggiungere dei nuovi sotto nodi, io potrò sapere quali ha aggiunto utilizzando un observer childAdded. Oppure se verrà eliminato un nodo, io potrò essere notificato dell’accaduto tramite un observer in modalità childRemoved.

Capita la logica, vediamo insieme come utilizzarli!

Il metodo observe

Il metodo che dovrai utilizzare si chiama observe (chi l’avrebbe mai detto) e viene attaccato ad un particolare nodo per osservarne gli eventi descritti dal DataEventType.

Il metodo ha due parametri:

  1. eventType: Un case dell’enum DataEventType. Cioè quelli che ti ho elencato sopra .value .childAdded .childRemoved e così via
  2. with: Una closure che ha come parametro un oggetto chiamato DataSnapshot che contiene un Any con il dato acchiappato dall’observer.

Più facile ad utilizzarlo che a descriverlo.

Aggiungi il seguente codice all’interno del tuo viewDidLoad:

L’observe che ho aggiunto al childutenti” legge l’evento DataEventType.value (cioè tutti gli eventi che si verificano sul nodo).

La closure viene richiamata quando firebase restituisce i dati richiesti dall’observer (se non ti ricordi cos’è una closure leggi questo tutorial del corso gratuito sul linguaggio swift). I dati vengono conservati dentro l’oggetto snap che è di tipo DataSnapshot.

All’interno della closure ho stampato il contenuto dello snap:

observe-value-firebase-realtime-database-linguaggio-swift-ios

Pazzesco no?

Estrarre i dati dal DataSnapshot

Un DataSnapshot è una fotografia del nodo nel momento in cui viene intercettato l’evento. Questo vuol dire che, nel momento in cui un dato viene modificato mentre si sta leggendo lo snap, quell’aggiornamento verrà intercettato dall’evento successivo.

Il valore trasportato dallo snap viene conservato nella proprietà value che è un Any opzionale nel caso in cui l’observer non riesca a trovare dei dati all’interno del nodo. 

Puoi castare questo oggetto nel tipo di dato che contiene il nodo per poterlo trattare all’interno dell’applicazione.

Nel nostro caso, dentro il nodo utenti, c’è un dizionario di dizionari. Dove ogni chiave è il nome dell’utente ed il valore associato il dizionario che contiene i suoi dati.

  1. Controllo che lo snapshot contenga dei dati. Infatti i dati reali sono contenuti dentro alla sua proprietà value
  2. Trasformo il value che è un Any in un [String : Any] dato che i dati del nodo utenti sono rinchiusi in un dizionario
  3. Eseguo il ciclo che mi scorre tutti i valori contenuti nel dizionario. La key conterrà la chiave dell’utente, per esempio “xcoderA”, mentre il value il dizionario che si trova all’interno
  4. Dato che value l’ho considerato un Any (vedi il punto 2), devo convertirlo nel suo tipo reale che, a sua volta, è un [String:Any] dato che i suoi valori sono sia String (come il nome e l’età) che Int (la chiave n_note)
  5. Estratto i valori dal dizionario dell’utente e li casto nel loro tipo reale

Se dovessi aver avuto dei problemi in questa parte, lasciami pure un commento e vedrò di aiutarti. Non aver paura, ci siamo passati tutti! 

Evitare l’observe .value

Ma come? ora che me lo hai fatto conoscere mi dici di non usarlo?

C’è un motivo e voglio fartelo vedere.

Se adesso provi a modificare, cancellare etc un dato dal nodo utenti il tuo observe .value verrà riavviato.

Questo significa che ri-scaricherà tutti i nodi ed i sotto nodi contenuti dal nodo utenti anche se tu dovessi muovere una virgola. Provare per credere, fai qualche modifica al database mentre hai l’app avviata e guarda cosa accade in console.

Cosa usare allora?

ObserveSingleEvent

Nel caso in cui volessi osservare per una sola volta i dati di un nodo, potrai utilizzare il metodo observeSingleEvent. Il metodo d’utilizzo è uguale al precedente, con l’unica differenza che tutti gli eventi futuri non verranno acchiappati da questo observer:

Questo metodo è utilissimo per una buona prevenzione delle risorse messe a disposizione da Firebase. Ti ricordo che il limite del piano gratuito è di 100 utenti contemporaneamente connessi.

L’observeSingleEnvent ti permetterà di accedere singolarmente ad una risorse per poi scollegarti subito dopo.

Observe childAdded

Una delle alternative migliori, all’evento .value per la lettura dei dati, è quella di utilizzare il .childAdded. 

Il childAdded funziona così:

  • La prima volta che viene avviato legge tutti i sotto nodi presenti nel nodo a cui viene attaccato.
  • Una volta letti tutti, quando verrà aggiunti nuovi child al nodo assegnato verrà restituito lo snap del nuovo child.

Puoi tradurlo così: Leggi, uno per volta, tutti i child presenti nel nodo e poi rimani in attesa che ne vengano aggiunti di nuovi.

Vediamo insieme con un esempio.

esempio-struttura-database-per-evento-childadded

Sono loggato dentro l’app con l’utente xcoderA e voglio recuperare le mie note per stamparle in una tabella. Per risolvere questo problema potrei attaccare un observe .childAdded al nodo note/xcoderA:

Cosa mi butterà fuori lo snap?

Ti aiuto io (oppure fai un print e osserva la console).

Se sei stato attento, ti ho detto che il .childAdded legge i nodi uno per volta. Quindi, dentro lo snap, ci sarà un singolo child. Questo significa che snap.value sarà un dizionario contente i valori della nota, quindi la descrizione ed il titolo.

L’observe essendo di tipo childAdded non risponderà alle modifiche che avverranno ai vari nodi, bensì verrà svegliato solamente quando si inserirà un child sotto “note“.

Un sistema decisamente più semplice, sicuro e meno pesante dal punto di vista computazionale.

Quando ti capita, quindi, cerca di usare questo evento rispetto al value.

Rimuovere un Observer

Gli observer classici, cioè che non sono di tipo observeSingleEvent, rimangono in ascolto per tutta la vita dell’applicazione.

Spesso e volentieri, per il discorso fatto sopra, è consigliato bloccarli o eliminarli quando questi non sono più utili per l’app.

Il metodo observe restituisce un numero Int che può essere utilizzato per arrestare l’esecuzione dell’observer.

Per arrestare un observe puoi utilizzare il metodo removeObserver(withHandle: UInt), sul nodo in cui è stato attaccato l’observerche accetta in ingresso l’id dell’observer da arrestare:

In alternativa puoi utilizzare il removeAllObservers per eliminarli tutti:

Lo ripeto, per rimuovere un observer devi invocare uno dei due metodi proposti nel rispettivo nodo d’appartenenza. Altrimenti non verranno eliminati. Allo stesso modo, il removeAllObservers, non elimina tutti gli observers dei sotto nodi ma solo quelli del nodo in cui viene invocato.

Ordinare i dati del Database

Vengono dette Query quei comandi che vengono interpretati dai database e che permettono a questo di poter elaborare i suoi dati in base a delle particolari condizioni espresse nel comando (la Query).

Per esempio, se io avessi una lista di punteggi di un giocatore e li volessi ordinare per punteggio decrescente, chiederei al database di farlo tramite una query.

Firebase database realtime query swift ios xcode

Il Database Realtime di Firebase utilizza questo sistema di domande, o query, per poter cambiare il risultato restituito dagli observer. Quindi, queste query vengono eseguite prima di attaccare un observer ad un nodo.

Si può ordinare il risultato di un observe utilizzando una delle seguente query:

  • queryOrderedByKey: Ordina il risultato prendendo in considerazione le chiavi del nodo. Per esempio, se un nodo ha come chiavi “B”, “C”, “A”, l’observer ordinerà le chiavi in ordine alfabetico, quindi “A”, “B”, “C”.
  • queryOrderedByValue: Ordina il risultato prendendo in considerazioni i valori associati alle varie chiavi del nodo.
  • queryOrderedBy(byChild: String): Ordina prendendo in considerazione il valore di una delle chiavi del sotto nodo.
  • queryOrderedByPriority: Ordina per priorità assegnate al nodo. Non ho trattato questo aspetto e quindi lo lascio in sospeso (in caso chiedimi per commento).

QueryOrderedByValue

Per esempio, nel database ho creato un nodo punteggi, dove ci sono come chiavi i nomi degli utenti e come valori i punteggi. Per leggere i dati in maniera ordinata ti basterà scrivere:

Successivamente dovrai far partire l’observer con tipologia d’evento .childAdded:

Ti ricordo che l’evento .childAdded attiva l’observer, la prima volta su tutti i nodi presenti e successivamente per ogni sotto nodo aggiunto. Questo farà si che alla prima esecuzione stampi tutti i nodi in maniera ordinata:

Invece d’usare il .childAdded che viene invocato per ogni nodo, non posso usare l’evento .value?

L’evento .value non restituisce il dato corretto della query. É probabile, ma non sono sicuro, che il motivo derivi dal fatto che con il .childAdded si eviti quel famoso problema della concorrenza tra gli utenti. Infatti l’ordinamento dei dati, o in generale le query, possono impiegare del tempo per essere eseguite e quindi si verrebbero a creare delle discrepanze o dei rallentamenti con l’interazione con il DB.

QueryOrderedByChild

Ho un’app in cui vengono pubblicati dei posts che gli utenti possono leggere. Ogni volta che un utente legge un post viene incrementata la proproprietà views.

queryOrderedByChild firebase realtime linguaggio swift ios

Oltre alla visualizzazione ordinata cronologicamente (data di default dall’autoId) vorrei mostrare i miei articoli in base al numero di views.

In questo caso non posso utilizzare il queryOrderedByValue sul nodo posts perché la proprietà views si trova all’interno dei singoli post.

Per ordinarli dovrò utilizzare il queryOrderedByChild sul nodo posts che mi permetterà di accedere ad una proprietà intera di ogni singolo post. Questo funzionerà perché il .childAdded legge ogni singolo post (come se si attaccasse al nodo idX) e per questo il queryOrderedByChild potrà leggere la proprietà views:

Ed ecco che magicamente ci tira fuori i posts ordinati per views:

Filtrare i dati

Oltre alle classiche operazioni di ordinamento, è possibile abbinare dei filtri agli observer in modo da cercare solo una tipologia di dato ben specifica.

I metodi in questione sono:

  • queryLimited(toFirst: Int): Restituisce i primi N elementi passati al parametro.
  • queryLimited(toLast: Int): Restituisce gli ultimi N elementi.
  • queryStartating(atValue: Any?): Restituisce N elementi che hanno un valore maggiore o uguale al valore di startValue (un numero, una stringa o un carattere).  Per esempio, se vuoi cercare tutti gli utenti che hanno per nome “paperino”, questo è il metodo che fa per te.
  • queryEnding(atValue: Any?): L’opposto del precedente. Esempio, se vuoi cercare tutti gli utenti che hanno il nome che finisce per “sapienza”.
  • queryEqual(toValue: Any?): Restituisce gli elementi che sono uguali al value passato alla funzione.

Questi metodi possono essere usati singolarmente oppure in combinazione con i metodi di ordinamento. Per esempio, se voglio stampare il post che ha il numero maggiore di views userei il .queryOrdered(byChild) in combinazione con il queryLimited(toLast):

  1. Perché l’observeSingleEvent e non l’observe?
    In questo modo, dato che voglio un solo elemento, l’observe verrà invocato una sola volta e poi distrutto.
  2. Perché il queryLimited(toLast)?
    L’ordinamento che utilizza il queryOrdered è crescente. Quindi il più grande è l’ultimo elemento restituito dall’observe. Con il queryLimited(toLast: 1) riesco a prendere solamente l’ultimo valore.

Una cosa importante da ricordare è che non puoi unire né due query di ordinamento né due query di filtraggio nella stessa istruzione.

Considerazioni

Per qualsiasi problema o vuoi un consiglio su come strutturare i tuoi dati, scrivimi pure un commento qui sotto. Firebase è eccezionale se usato correttamente, quindi non aver timore di chiedere qualsiasi cosa.

Ormai il mondo va verso la velocità dello sviluppo. Utilizzare un app come questa ti permette di risparmiare tempo e sopratutto denaro dato che i costi sono davvero irrisori se paragonati agli strumenti e capacità che mette a disposizione.

Io ormai la utilizzo quasi per tutti i progetti. Ha potenzialità che vanno ben oltre il normale database: Analytics, login, Machine Learning, Crash Analytics ed A/B Testing. Cosa che, se le dovessi sviluppare da solo o in team, impiegheremmo mesi se non addirittura anni.

Se vuoi continuare con Firebase ho scritto un altro tutorial sul Login e Signup con Firebase. Nel frattempo, comincia a prendere confidenza con il Database Realtime di firebase con il linguaggio Swift.

Buona Programmazione!

Start typing and press Enter to search

Autenticazione con Firebase e linguaggio Swift