Core Data
Panoramica e
utilizzo
Marco Nobile
Matricola: 0000653725
Introduzione
Core Data è un framework per la persistenza dei dati introdotto da Apple per iOS (e
Mac OS X). Si compone di una serie di API che permettono di organizzare i dati
tramite il modello relazionale, serializzato tramite codifica XML, binaria o secondo i
protocolli SQLite.
Tutti i dati possono, grazie a Core Data, essere manipolati tramite oggetti di più alto
livello che rappresentano le Entità e le loro Relazioni.
Core Data assolve molti dei “doveri” di un Modello in una architettura MVC
(Model-View-Controller), si occupa di gestire le modifiche ai dati, la serializzazione
su disco, e le queries, il tutto cercando di minimizzare l’utilizzo di memoria.
Oltre a questo, Core Data presenta altre features interessanti:
●
●
●
●
Validazione automatica dei valori delle proprietà
Gestione sicura della migrazione dello schema
Supporto completo e automatico per la codifica e l’osservazione chiave-valore
Supporto automatico per memorizzare oggetti in repositories esterni
Perchè utilizzare Core Data?
Ricapitolando, è conveniente utilizzare questo framework nello sviluppo di
applicazioni iOS per le seguenti ragioni:
● Diminuzione considerevole del numero di righe di codice da scrivere nello
sviluppo del Model (dal 50% al 70%)
● Ha alla base del codice ottimizzato e viene periodicamente aggiornato.
● Possiede un Tool di modellazione grafica che permette la creazione di schemi
anche complessi in modo semplice e intuitivo.
● Integrato con Interface Builder permette di creare UI dai modelli.
Stack di Core Data
Il Framework Core Data consiste di alcuni oggetti che, integrati, provvedono alle
funzionalità di archiviazione. Questi vengono rappresentati in figura.
1 Managed Object Context
Il codice dell’Applicazione iOS interagisce direttamente con questo oggetto (invece
che con la base dati). Questo Context mantiene lo status degli oggetti e gestisce le
loro relazioni. Tutte le interazioni col database sottostante sono mantenute
temporaneamente in questo strato, fino a quando l’utente non specifica di salvare i
cambiamenti permanentemente.
Managed Objects
Istanze della classe NSManagedObject, possono essere rappresentate come dei
records in un tabella di un database relazionale.
Managed Object Model
Definisce il modello di un oggetto, analogamente ad un’entità. Infatti sono proprio le
entità che definiscono il modello dei Managed Objects. Ogni oggetto avrà quindi un
set di attributi, relazioni (one-to-one, one-to-many...), proprietà che possono essere
accedute anche da altre entità(o Managed Objects), e una serie di richieste (query
predefinite che possono essere utilizzate per estrapolare delle informazioni specifiche
da un Object Model).
2 Persistent Store Coordinator
E’ il responsabile della coordinazione degli accessi a multipli “Persistent Object
Store” (definiti in seguito). Lo sviluppatore non interagirà mai direttamente con
questo oggetto. Quando, raramente, è presente più di un Persistent Object Store, il
Coordinator di occupa di presentarlo allo strato superiore come un unico store.
Persistent Object Store
E’ lo strato più basso della pila di Core Data, nel quale i dati vengono memorizzati.
Vengono supportate le codifiche XML, binaria e SQLite(utilizzata di default dall’iOS
SDK).
Sviluppare App che utilizzano Core Data
Di seguito verranno esplicati alcuni dei procedimenti chiave per integrare e utilizzare
il framework Core Data in una applicazione iOS
Creare un nuovo progetto includendo Core Data
Per prima cosa, dobbiamo creare un progetto in XCode, dal quale poi partire a
sviluppare l’applicazione desiderata. Una volta arrivati alla finestra di dettaglio del
nuovo progetto, occorre abilitare la checkbox “Utilizza Core Data”
Una volta creato il progetto, in aggiunta ai files soliti di un classico nuovo progetto,
verrà creato anche un file speciale nominato: “NomeProgetto.xcdatamodeld”.
E’ in quest’ultimo file che le descrizioni delle varie entità del nostro datamodello
verranno memorizzate.
Creare e descrivere un’Entità
La descrizione di un’entità definisce il modello dei nostri dati. Per creare un’entità in
un’Applicazione Core Data, bisogna selezionare il file .xcdatamodeld(descritto
3 sopra), XCode si incaricherà di aprire l’editor delle entità (per poi autogenerare del
codice Swift). Si aprirà una finestra simile alla seguente:
E’ da notare che è possibile scegliere come visualizzare delle entità create: in maniera
testuale o graficamente come uno schema relazionale. Per cambiare modalità è
sufficiente selezionarla nell’angolo in basso a destra.
Per creare una nuova entità bisogna cliccare “Add Entity”. Una volta creata, basterà
cliccare due volte sopra di essa (XCode la posizionerà nell’elenco sotto “Entities”) per
modificarne il nome.
Se si desidera aggiungere degli attributi alle entità basterà utilizzare il bottone “Add
Attribute”, nel pannello di creazione attributo sarà necessario specificare il nome e il
tipo dell’attributo( analogamente ad uno schema ER ).
Generare una sottoclasse di NSManagedObject
Come spiegato inizialmente, ad ogni datamodello (o entità), viene associata
un’istanza della classe NSManagedObject, è quindi necessario estendere questa
classe per modellare le diverse entità.
Con XCode è possibile autogenerare il codice di queste sottoclassi, basta selezionare
“Editor -> Create -> NSManagedObject Subclass...”. Nella finestra che compare in
seguito bisognerà selezionare prima il datamodello, poi le entità di quest’ultimo da
generare. Una volta terminata la procedura, viene creato dal sistema un file
“NomeEntità.swift”, contenente la sottoclasse di NSManagedObject corrispondente
all’entità.
4 Esempio di sottoclasse generata:
import Foundation
import CoreData
class NomeEntità: NSManagedObject {
@NSManaged var attributo1: Int
@NSManaged var attributo2: String
}
Modifica del nome della classe riferita all’Entità
Quando si utilizza Core Data con del codice Swift, è importante includere il nome
dell’applicazione come parte del nome della classe, così da includerla nel suo
namespace. Per effettuare questa modifica, basta aprire l’editor del file
.xcdatamodeld, selezionare l’entità e aprire il Data Model Inspector nel pannello
Utilities, basterà per esempio, cambiare il nome della Classe in questo modo:
NomeEntità → NomeProgetto.NomeEntità
​
Salvataggio dei dati su Persistent Store
Quando, nella nostra applicazione, abbiamo bisogno di salvare un’entità in modo
permanente, abbiamo bisogno di un’istanza di Managed Object Context, per
ottenerla, basta seguire le linee di codice seguenti:
let managedObjectContext =
(UIApplication.sharedApplication().delegate
as!
AppDelegate).managedObjectContext
Di seguito, bisogna ottenere la descrizione dell’Entità desiderata, dunque creare una
nuova istanza della sottoclasse corrispondente. Infine, bisogna istruire il Context di
salvare i dati caricati, e intercettare un possibile errore per poterlo gestire.
5 let entityDescription =
NSEntityDescription.entityForName("NomeEntità",
inManagedObjectContext: managedObjectContext!)
let entity = NomeEntità(entity: entityDescription!,
insertIntoManagedObjectContext:
managedObjectContext)
entity.attributo1 = 10
entity.attributo2 = “Stringa”
var error: NSError?
managedObjectContext?.save(&error)
if let err = error {
//handle error
}
Caricamento di dati dal Persistent Store
Così come salvare i dati, un’applicazione potrebbe ragionevolmente avere la necessità
di cercare e estrapolare dal database delle informazioni riguardanti le entità salvate.
Anche in questo caso bisogna ottenere la descrizione dell’Entità che si cerca, poi
creare un “predicato” che specifichi, per esempio, che solo gli oggetti con un dato
valore per un dato attributo vengano inseriti nel risultato della ricerca.
Questo risultato poi è rappresentato da un array, dal quale, per ogni elemento, è
possibile estrapolare gli attributi tramite il metodo “valueForKey”.
Un esempio di implementazione si trova alla pagina seguente.
6 let entityDescription =
NSEntityDescription.entityForName("NomeEntità",
inManagedObjectContext: managedObjectContext!)
let request = NSFetchRequest
request.entity = entityDescription
let pred = NSPredicate(format: "(attributo1 = %@)", 10)
request.predicate = pred
var error: NSError?
var objects = managedObjectContext?.executeFetchRequest(request,
error: &error)
if let results = objects {
if results.count > 0 {
let match = results[0] as! NSManagedObject
// handle here the single result using
// “match.valueForKey(..)”
} else {
status.text = "No Match"
}
}
7