IOS CloudKit
Corso di Programmazione di Sistemi Mobile
Mattia Borrillo
Matr: 0000656937
Dire che un’app è cloud based significa che alcuni dati utilizzati nella stessa vengono
salvati in server online come quelli iCloud.
Apple, per permetterti di salvare dati ed informazioni sui propri server, ti mette a
disposizione un framework chiamato CloudKit.
La bellezza di affidarsi ad un servizio come quello offerto da iCloud sta nella
semplicità di implementazione e nella sicurezza che ne derivano i dati in esso inseriti.
Molti pensano che il Cloud è qualcosa di poco affidabile, ma non è assolutamente
vero, uno dei vantaggi del cloud è che esendo un sistema distribuito,i dati sono anche
difficili da recuperare da parte di eventuali attacchi informatici.
Il CloudKit è lo strumento, offerto agli sviluppatori, per interfacciare i dati della
propria applicazione ad uno spazio dedicato all’interno dei server Apple. I dati,
inseriti nel cloud, possono essere condivisi con gli altri utenti oppure mantenuti
privati.
Tre motivi per affidarsi ad iCloud tramite il CloudKit.
•
Semplicità di utilizzo : Per avere il permesso di utilizzare il CloudKit, e quindi
permettere alla tua applicazione di conservare dati sui server iCloud, è
necessario registrarsi al Developer Program. Questo farà si che Apple configuri
in automatico uno spazio dedicato alla conservazione delle informazioni delle
tue applicazioni.
Dal lato dell’utilizzatore della tua applicazioni, il CloudKit evita la creazione
di fastidiosi moduli di registrazione dato che vengono utilizzati di default le
credenziali dell’account iCloud che ogni utente Apple possiede.
In pratica un utente che utilizza un’app con CloudKit è già di default loggato
nello spazio cloud dedicato.
•
Sicurezza : tutte le informazioni vengono salvate sui server Apple, quindi
utilizzare il CloudKit è sinonimo di sicurezza. In più i dati non possono essere
trattati se non nei limiti imposti dal regolamento Apple e dalle norme vigenti in
maniera di tutela della privacy Americana.
Non è da sottovalutare questo aspetto, molte compagnie online non ti
impongono di trattare e tutelare i dati degli utilizzatori della tua applicazione e
per questo, molti potrebbero sbandierare i tuoi dati a società terze come quelle
pubblicitarie.
•
Costi : Apple ti offre una quantità di storage gratuito che non può neanche
lontanamente essere paragonato a quello che gli altri servizi mettono sul
mercato.
Abilitare le funzionalità del CloudKit.
Prima di cominciare bisogna modificare il Bundle Identifier dell'applicazione e
assicurarsi di essere loggato con l’account sviluppatore.
Per evitare la nascita di errori futuri bisogna utilizzare un Identifier unico. Ad
esempio utilizzare la seguente sintassi:
• it.tuoDominio.nomeApp
• tuoDominio.nomeApp
Se non hai un dominio puoi mettere anche il tuo nome, l’importante è che sia seguito
dalla dot notation e dal nome della tua applicazione.
Per poter interfacciare l'applicazione con iCloud, vai nel menu Capabilities e poi
passa su On la voce iCloud: adesso che la tua app è pronta a connettersi ai server
iCloud, serve anche uno spazio in cui poter conservare le informazioni pubbliche e
private dei tuoi utenti. Lo spazio di memorizzazione prende il nome di Container e
per abilitarlo devi spuntare la casella CloudKit nel menù apparso una volt posizionato
lo switch sull'ON.
Il Container della tua applicazione ha un identificativo che è dato dall’unione della
parola iCloud seguita dal tuo Bundle Identifier e deve obbligatoriamente trovarsi in
questa forma, quindi non modificarlo.
CloudKit DashBoard
La tua app è pronta ad utilizzare il CloudKit e a connettersi con i server iCloud. Per
poter accedere all’aria riservata alla gestione dei dati, premi il bottone “CloudKit
Dashboard” oppure collegati dal seguente link:
https://icloud.developer.apple.com/dashboard/.
Nel Container puoi inserire 3 tipi di “oggetti”, definiti e gestiti nell’area “SCHEMA“,
chiamati: Record Types, Security Roles e Subscription Types.
Per poter salvare dati sul cloud è sufficiente l'utilizzo dei Record Types.
Il principio di funzionamento del salvataggio dei dati su iCloud non si discosta molto
dai principi della programmazione ad oggetti.
Apple ha ben pensato di catalogare le informazioni a blocchi o per meglio dire in
Record.
Un Record Type è l’equivalente di una Classe in OOP. Una volta che si crea un
Record, al suo interno si potranno creare gli attributi che ne rappresenteranno lo stato.
Es. di classe.
class Nota {
var titolo :String?
var testo :String?
init(titolo: String, testo: String) {
self.titolo = titolo
self.testo = testo
}
}
Creare un Record Type
Una volta che si ha idea dell’oggetto che vuoi salvare su iCloud è tempo di creare un
Record che ne rappresenti le caratteristiche.
Dal menu SCHEMA, selezionare Record Types e premere il tasto + per aggiungere
un nuovo Record.
Rinonimare il Record in “Nota“ (o comunque il nome che si vuole attribuire a questo
nuovo tipo di dato), cambiare l’attributo creato in “titolo” e infine aggiungere un
nuovo attributo di tipo String chiamato “testo“, per salvare il Record Type premere
Save. (Di seguito aggiungere tutti gli attributi che si vogliono salvare sul cloud
dell'oggetto)
Public Data e Private Data, le politiche di sicurezza dei dati.
Ora che si ha un modello per il salvataggio dei dati dell'applicazione su iCloud è
necessario domandarsi come questi dati vengano gestiti.
Se tutti gli utilizzatori dell'applicazione utilizzano lo stesso spazio iCloud, vuol dire
che i miei dati possono essere letti anche da altri utenti?
No, ci sono 2 aree dove vengono salvati i dati di ogni utente, la Public Data e la
Private Data.
Nella Public Data vengono inseriti tutti i Record types che vogliono essere condivisi
con tutti gli utilizzatori dell'applicazione. Se ad esempio l’applicazione utilizza dei
dati che servono a tutti gli utenti, allora il record andrà inserito in questa sezione.
All’interno della Public Data sono presenti 2 sezioni:
1. User Records: nella sezione Record Types era presente un Record chiamato
User. Esso rappresenta gli utilizzatori della tua applicazione e i vari dati che
associ all’User vengono conservati qui.
2. Default Zone: in questa sezione vengono salvati tutti i Record Types pubblici e
diversi da quelli User.
La Private Data è la zone in cui salvare i record types privati.
Un Record Types non ha un posto di default in cui si trova e pertanto da codice si
possono smistare i vari dati nella relativa zona.
Lo sviluppatore dell’applicazione non ha accesso alla Default Zone privata di ogni
utente della sua applicazione.
CloudController, CKContainer e CKDatabase.
Come prima cosa importa il CloudKit sotto l’import già presente:
import CloudKit
class CloudController {
/*Il CKContainer è il riferimento allo spazio di memoria dedicato all'applicazione. In
sostanza è il contenitore di tutti i file, pubblici e privati.
IL CKDatabase è l'effettivo riferimento allo spazio pubblico/privato del Container
*/
var container : CKContainer
var publicDB : CKDatabase
let privateDB : CKDatabase
}
Creare una connessione con iCloud mediante il CloudKit fa sì che venga realizzato
uno spazio di memoria dedicato a tutti i dati dell’applicazione, il nome di questo
spazio è Container.
Per questo motivo la variabile “container” non sarà altro che il riferimento al
Container dell’applicazione.
All’interno Container si possono salvare Record, oggetti di tipo Record Types, con
due proprietà di sicurezza: pubblico e privato. Tutti i Record diversi da User vengono
salvati nella rispettiva Default Zone privata/pubblica.
Un CKDatabase è lo spazio pubblico o privato del Container, se il CKContainer
rappresenta l’intera nuvola, il CKDatabase è il riferimento sia alla Default Zone
privata che pubblica.
Ecco che così, il metodo init non fa altro che instanziare il container, prendere la
rispettiva zona privata/pubblica e assegnarla alle rispettive variabili. Sotto il
precedente codice aggiungi:
init() {
container = CKContainer.defaultContainer()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}
Come qualsiasi database, per recuperare e aggiungere dati, bisogna fare delle Query.
Per inziare si piò richiedere di aggiungere un Record (CKRecord) in un CKDatabase
oppure recuperare dati di una tipologia di Record type utilizzando una CKQuery.
Aggiungere un Record ad iCloud con CloudKit
All’interno della classe è necessario aggiungere il seguente metodo:
func salvaNota(titolo :String, testo :String) {
// creo un record di tipo "Nota"
let recordNota = CKRecord(recordType: "Nota")
// al record setto, titolo e testo uguali a quelli del parametro della funzione
recordNota.setValue(testo, forKey: "testo")
recordNota.setValue(titolo, forKey: "titolo")
/*
salvo nel Database Pubblico (la record zone public) il record appena creato
la funzione è una clousure e il corpo stampa un messaggio quando finisce di registrare
*/
publicDB.saveRecord(recordNota, completionHandler: { (record, error) -> Void in
println("Nota salvata con successo")
})
}
Il CKRecord è un oggetto di tipo Record Type, infatti dentro la sua inizializzazione
vuole in nome del Record Type a cui riferirsi. Nel tuo caso è “Nota” (quello creato
come eesempio durante il tutorial).
Per accedere al contenuto o modificarlo, il CKRecord, ti mette a disposizione il
metodo setValue(<valore>, forKey: <nomeChiave>).
Una volta modificati i value del record, viene salvato all’interno del Database con il
saveRecord. Il saveRecord viene eseguito dal database in cui vuoi effettivamente
salvare il record. Per rendere il record privato devi anche cambiare il database in cui
permutare l’azione. Sbagliando DB si possono causare grossi problemi di violazione
di privacy.
Recuperare uno o più Record con il CloudKit
Aggiungi un nuovo File al progetto (File\New File…) e seleziona Swift File,
chiamalo Nota e al suo interno inserisci il seguente codice:
import Foundation
import CloudKit
class Nota : NSObject {
var record : CKRecord! // il riferimento al Record che rappresenta la Nota
var titolo :String!
var testo :String!
var database : CKDatabase! // il database in cui è stata inserita il record/nota
var date: NSDate // la data di creazione del record
init(record : CKRecord, database: CKDatabase) {
self.record = record
self.database = database
self.titolo = record.objectForKey("titolo") as String
self.testo = record.objectForKey("testo") as String
self.date = record.creationDate
}
}
Tornare al CloudController.swift, e sopra la definizione della classe, creare un
Protocol (una Interfaccia per chi proviene da altri linguaggi di programmazione) con
2 metodi all’interno che verranno richiamati dal ViewController :
protocol CloudControllerDelegate {
func errorUpdating(error: NSError)
func modelUpdated()
}
Adesso all’interno della classe CloudController, aggiungi i seguenti attributi:
var noteArray = [Nota]() // conterrà tutti i Record recuperati dal Container.
var delegate : CloudControllerDelegate?
Il metodo per il recupero dei dati dall’iCloud è il seguente:
func recuperaNote() {
//Il predicate è il modo in cui i dati devono essere recuperati
// La CKQuery è il tipo di domanda da fare al database. In particolare si sta richiedendo tutti i tipi record di tipo "Nota" con
nessun tipo di filtro (dato che predicate non è impostato)
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "Nota", predicate: predicate)
publicDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in
if error != nil {
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.errorUpdating(error)
return
}
} else {
self.noteArray.removeAll(keepCapacity: true)
for record in results {
var nota = Nota(record: record as CKRecord, database: self.publicDB)
self.noteArray.append(nota)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.modelUpdated()//utilizzare i dati appena recuperati
return
}
}
}
Una CKQuery è la domanda che viene fatta al CKDatabase per recuperare una
tipologia di contenuti o per meglio dire record. Dato che possono esistere, in un
CKDatabase, migliaia di record una query può essere effettuata impostando dei filtri
di ricerca chiamati NSPredicate.
Se non se ne fa uso, non va messo nil nella CKQuery, bensì un NSPredicate come
quello creato nel metodo.
Una CKQuery viene eseguita dal CKDatabase, dal quale vuoi recuperare i record,
mediante il metodo performQuery. Il primo parametro del metodo è la query da
eseguire mentre il secondo parametro, inZoneWithId, rappresenta l’ID della zona in
cui performare la Query.
La performQuery è una closure con 2 argomenti, results e error. Se l’esecuzione della
query ritorna un errore viene effettuata l'operazione utilizzando un dispatch_async in
quanto l’applicazione potrebbe bloccarsi perché ferma all’esecuzione della query.