I. Introduction▲
« Core Data » est la manière conventionnelle pour maintenir et gérer les données à la fois dans les applications iPhone et Mac, et avec Swift, c'est un peu plus simple. Ainsi, nous devrions prendre le temps de comprendre le core data lorsque nous concevons des applications. Désireux de voir ce que nous allons créer d'ici la fin de ce tutoriel ? Nous allons créer une vue avec le core data, la peupler avec des données, ajouter l'aptitude à effacer, insérer, et trier/rechercher des enregistrements. Ces données sont persistantes et demeurent même après une extinction complète de votre iPhone.
II. Notre première application▲
La première chose à savoir à propos du framework Core Data avant d'y plonger, est que ce n'est pas une base de données relationnelle bien qu'il utilise SQLite comme moteur de support, et il ne fait pas de correspondance objet à une base de données relationnelle non plus. Le support SQLite est plus un détail de réalisation, et en réalité les fichiers binaires ou listes de propriétés peuvent être utilisés à la place.
La documentation officielle d'Apple décrit le Core Data ainsi :
« Le framework Core Data fournit des solutions généralisées et automatisées à des tâches communes associées avec le cycle de vie du monde orienté objet et la gestion graphique de l'objet, incluant la persistance. »
Avant que nous n'allions trop dans la technique à propos du Core Data, je pense qu'il est utile de commencer à jouer un peu avec l'Interface de Programmation d'Application (API).
Créez un nouveau projet Xcode 6 en utilisant un template à vue simple, avec Swift comme langage, et Core data activé. Je vais appeler le projet MyLog.
En regardant le fichier AppDelegate.swift, vous noterez qu'utiliser cette option aura ajouté pas mal de fonctions. La plupart d'entre elles pour la mise en place de la pile core data. Les options par défaut sont maintenant judicieuses. Le premier objet qui nécessite d'être utilisé avec Core Data est le managedObjectContext défini ici. Si vous utilisiez le template de Core Data comme montré plus haut, ce code serait déjà présent.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
lazy
var
managedObjectContext
:
NSManagedObjectContext
?
=
{
// Retourne le contexte de l'objet géré pour l'application (qui est déjà lié au coordonnateur de la mémoire persistante pour l'application.)
// Cette propriété est facultative depuis qu'il y a erreur légitime
// conditions qui pourraient entraîner l'échec de la création d'un contexte.
let
coordinator
=
self
.
persistentStoreCoordinator
if
coordinator
==
nil
{
return
nil
}
var
managedObjectContext
=
NSManagedObjectContext
()
managedObjectContext
.
persistentStoreCoordinator
=
coordinator
return
managedObjectContext
}()
Tout ce que vous avez besoin de savoir à ce propos, est que managedObjectContext est une variable paresseuse sur AppDelegate qui peut être utilisée dans des appels Core Data en cours d'exécution. Sachant cela, nous pouvons accéder au managedObjectContext depuis notre fichier ViewController.swift. Par exemple, dans la méthode viewDidLoad() de ce fichier, nous pouvons utiliser ce code afin d'imprimer la description de managedObjectContext à la console (les nouvelles lignes sont surlignées).
2.
3.
4.
5.
6.
7.
8.
9.
10.
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
// Effectuer une configuration supplémentaire après le chargement de la vue, généralement à partir d'un nib.
// Récupérer le managedObjectContext de AppDelegate
let
managedObjectContext
=
(
UIApplication
.
sharedApplication
().
delegate
as
!
AppDelegate
).
managedObjectContext
// Afficher à la console
println
(
managedObjectContext
)
}
Nous accéderons au managedObjectContext assez fréquemment ; à cette fin, nous devrions le sortir de la méthode viewDidLoad() et le déplacer dans une zone où nous pouvons accéder aisément. Pourquoi ne pas stocker simplement cela comme une variable d'instance de ViewController ?
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
import
UIKit
class
ViewController
:
UIViewController
{
// Récupérer le managedObjectContext de AppDelegate
let
managedObjectContext
=
(
UIApplication
.
sharedApplication
().
delegate
as
!
AppDelegate
).
managedObjectContext
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
// Effectuer une configuration supplémentaire après le chargement de la vue, généralement à partir d'un nib.
// Afficher à la console
println
(
managedObjectContext
)
}
override
func
didReceiveMemoryWarning
()
{
super
.
didReceiveMemoryWarning
()
// Dispose of any resources that can be recreated.
}
}
La variable managedObjectContext est calculée en utilisant le managedObjectContext existant dans le délégué d'application. Dans la méthode viewDidLoad(), nous définissons cette variable par l'intermédiaire de la console. Si votre application est bien paramétrée, vous devriez voir quelque chose comme ceci :
Optional(<NSManagedObjectContext: 0x7fe68b58c800>)
Vous noterez que le template Xcode a créé un fichier additionnel : MyLog.xcdatamodeld.
En ouvrant ce fichier, vous pouvez voir l'éditeur de modèle Core Data. Ajoutons une nouvelle entité Core Data, appelée LogItem . Notre application de journalisation montrera une liste de LogItems qui contiennent un peu de texte.
Cliquez sur le bouton « Add Entity », puis sur le panneau contextuel, sélectionnez « Data Model Inspector ». Ainsi, nous pouvons modifier le nom par défaut « Entity » en «LogItem ».
Ensuite, en dessous, nous pouvons ajouter notre premier attribut en appuyant sur le bouton « + Attribute ».
Nommez cet attribut title, et donnez-lui une instance de type chaîne de caractères. Nous ajouterons aussi un second attribut de ce type, appelé itemText.
À partir de ce point, tout changement que vous appliquez à votre Core Data, tel qu'ajouter une nouvelle entité ou un nouvel attribut mènera à une incohérence dans le modèle de l'application dans le simulateur d'iPhone. Si cela vous arrive, vous obtiendrez un crash vraiment effrayant dans vos applications dès qu'elles démarrent. Vous verrez aussi quelque chose de pareil à l'extrémité en bas de votre console, « reason=The model used to open the store is incompatible with the one used to create the store ».
Si cela vous arrive, il y a une solution aisée :
dans le simulateur d'iPhone, ou sur votre appareil, effacez simplement l'application, puis lancez une nouvelle commande « Build & Run » dans Xcode. Cela va effacer toute version désuète de votre modèle, et vous permettra d'exécuter un lancement neuf.
Maintenant que nous avons notre première entité créée, nous voulons aussi être capables d'accéder directement à celle-ci comme si c'était une classe dans notre code. Xcode fournit un outil automatisé pour faire cela. Dans la barre de menu, sélectionnez Editor->Create NSManagedObject Subclass…
Dans la première boîte de dialogue, cochez le modèle MyLog et sélectionnez « Suivant ». Ensuite, cochez l'entité LogItem, et sélectionnez à nouveau « Suivant ».
Une fenêtre de sauvegarde de fichier devrait apparaître avec une option pour spécifier le langage, choisissez Swift. Finalement, sélectionnez « Créer », et vous devriez maintenant voir un fichier LogItem.swift ajouté.
Son contenu devrait être quelque chose de semblable à ce qui suit :
2.
3.
4.
5.
6.
7.
import
Foundation
import
CoreData
class
LogItem
:
NSManagedObject
{
@NSManaged
var
title
:
String
@NSManaged
var
itemText
:
String
}
Cette classe est générée depuis le fichier xcmetamodeld. L'entité que nous avons créée est représentée par la classe pareillement nommée LogItem, et les attributs sont changés en variables en utilisant l'identifiant @NSManaged , qui donne une traitement spécial aux variables, leur permettant d'opérer avec Core Data. Cependant pour la plupart des intentions et des propos, vous pouvez simplement les considérer comme des variables d'instance.
Compte tenu de la manière dont les modules Swift fonctionnent, nous avons besoin de modifier le modèle du Core Data. Dans le champ Class dans l'inspecteur de modèle de notre entité, LogItem, nous avons besoin de spécifier le nom de projet comme préfixe au nom de classe. Ainsi, à la place de LogItem comme classe, il faut écrire MyLog.LogItem, en admettant que votre application soit MyLog.
Dans notre fichier viewController.swift, dans la méthode viewDidLoad(), créons des instances de LogItem. Il existe plusieurs manières pour le faire, mais la moins dispensaire en langage est d'utiliser la méthode insertNewObjectForEntityForName de NSEntityDescription.
2.
3.
4.
5.
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
let
newItem
=
NSEntityDescription
.
insertNewObjectForEntityForName
(
"LogItem"
,
inManagedObjectContext
:
self
.
managedObjectContext
!)
as
!
LogItem
}
Ici, nous insérons un nouvel objet dans la pile de core data, via le managedObjectContext, que la fonction de maquette ajoutera à AppDelegate pour nous. Cette méthode retourne un NSManaged Object qui est un type générique d'objet de Core Data, qui répond aux méthodes comme valueForKey (valeur pour clé). Si vous ne comprenez pas tout à fait ce que cela signifie, ne vous en souciez pas trop, cela ne vous empêchera pas d'être capable d'utiliser Core Data. Continuons.
Avec une version NSManagedObject de newItem, nous pourrions faire newItem.valueForKey("title") pour obtenir le titre. Mais ce n'est pas la meilleure approche, parce que cela laisse trop d'opportunités pour mal orthographier un nom d'attribut, ou obtenir le mauvais objet de manière inattendue et avoir de cruels bogues en essayant d'accéder à ces attributs.
Ainsi, dans notre cas, nous attribuons le NSManagedObject que insertNewObjectForEntityForName retourne à notre classe générée, LogItem.
Cela signifie simplement ajouter en réglant le titre et le texte de l'élément ainsi :
2.
3.
4.
5.
6.
7.
8.
9.
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
// Effectuer une configuration supplémentaire après le chargement de la vue, généralement à partir d'un nib
let
newItem
=
NSEntityDescription
.
insertNewObjectForEntityForName
(
"LogItem"
,
inManagedObjectContext
:
self
.
managedObjectContext
!)
as
!
LogItem
newItem
.
title
=
"Wrote Core Data Tutorial"
newItem
.
itemText
=
"Wrote and post a tutorial on the basics of Core Data to blog."
}
Si nous n'avions pas généré notre fichier LogItem.swift plus tôt, le type LogItem n'aurait pas été défini et nous aurions été limités à travailler seulement avec les types NSManagedObject. Ce qui est une façon réellement terrible de travailler avec l'API Core Data, car cela conduit lourdement à déterminer les objets, classes, entités, états, et autres avec des comparaisons de chaînes de caractères induisant un temps d'exécution beaucoup plus long. Quelle horreur !
Maintenant que nous avons créé un nouvel objet, et défini son titre ainsi que son texte, nous pouvons effectuer une requête sur cet objet n'importe où dans notre application, afin de récupérer l'objet. Ignorons la fonction viewDidAppear() et réalisons une manière d'accéder aux informations de l'objet. Nous allons réaliser un fetch de Core Data (qui est comme une requête, si vous avez travaillé avec SQL auparavant), et présenter les contenus des colonnes obtenues dans une nouvelle fenêtre d'alerte.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
override
func
viewDidAppear
(
animated
:
Bool
)
{
super
.
viewDidAppear
(
animated
)
// Créer une nouvelle requête fetch en utilisant l'entité LogItem
let
fetchRequest
=
NSFetchRequest
(
entityName
:
"LogItem"
)
// Exécuter la requête fetch et ranger les résultats dans un tableau d'objets LogItem
if
let
fetchResults
=
managedObjectContext
!.
executeFetchRequest
(
fetchRequest
,
error
:
nil
)
as
?
[
LogItem
]
{
// Créer une alerte et définir son message
let
alert
=
UIAlertController
(
title
:
fetchResults
[
0
].
title
,
message
:
fetchResults
[
0
].
itemText
,
preferredStyle
:
.
Alert
)
// Afficher l'alerte
self
.
presentViewController
(
alert
,
animated
:
true
,
completion
:
nil
)
}
}
Premièrement, nous créons une nouvelle instance NSFetchRequest en utilisant l'entité LogItem.
Ensuite, nous créons une variable fetchResults en utilisant la méthode executeFetchRequest de managedObjectContext. La seule chose que nous avons spécifiée dans notre fetchRequest est l'entité, de telle sorte que ce fetch particulier retourne simplement chaque enregistrement. Si vous êtes familiers avec SQL, une requête fetch sans prédicat sur l'entité LogItem est quelque chose comme SELECT * FROM LogItem.
Ensuite, nous créons une instance UIAlertController pour afficher un message à l'écran, et régler ses propriétés de titre et de message selon ceux du premier objet du LogItem retourné par le fetch (qui est un tableau d'objets LogItem).
Lancez l'application, et vous devriez voir l'objet présenté à l'écran. Vous allez maintenant stocker et retourner des données depuis le Core Data. C'est la première étape pour construire des applications à stockage persistant.
Dans la partie 2, nous aborderons le travail à enregistrements multiples et en utilisant NSPredicate afin d'exécuter des requêtes filtrées.