SlideShare une entreprise Scribd logo
Simplifiez-vous CoreData
Avec MagicalRecord
CocoaHeads Rennes #13
Olivier Halligon
Septembre 2013
CoreData : rappels
• Framework Cocoa pour iOS et OSX
• Permet de gérer un graphe d’objets et sa persistance
• Gestion de relations
• Gestion des transactions, d’annulation…
• Gestion des futures (faulting)
• N’est pas une base de données relationnelle
• On peut l’utiliser en InMemory-only
• Peut faire persister les données dans une base SQLite mais aussi en XML
• On peut l’utiliser comme abstraction d’un WebService (via NSIncrementalStore)
Exemple de modèle de données
Complexité de CoreData
NSAtomic
StoreNSPersistent
Store
NSManagedObjectModel
NSFetchResult
Controller
NSAttribute
Description
NSManagedObjectID
NSEntityMapping
NSManagedObject
NSFetch
Request
NSManaged
ObjectContext
NSEntityDescription
NSIncremental
Store
NSPersistentStoreCoordinator
Complexité de CoreData
• Beaucoup de classes à prendre en main quand on commence
• Dont pour la plupart le rôle semble abstrait de prime abord
• Même si ça vient avec la pratique, peu encourageant au début
• Beaucoup de lignes de code pour des opérations simples
• Une dizaine de lignes rien que pour récupérer un objet dans notre graphe
• Du coup répétitif pour des actions fréquentes
• Nécessité d’utiliser des NSString pour décrire les noms d’entités à récupérer
• Pas d’autocomplétion, pas de vérification à la compilation
• Nécessité de transtyper (caster) les résultats
Exemple de Requête
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html#//apple_ref/doc/uid/TP40002484-SW1
- (void)logAllRennesSessions
{
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
// Set sort descriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[request setSortDescriptors:@[sortDescriptor]];
// Set predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"];
[request setPredicate:predicate];
NSArray *array = [moc executeFetchRequest:request error:nil];
if (array == nil)
{
NSLog(@"Some error occured");
}
else
{
NSLog(@"Sessions in Rennes: %@", array);
}
}
Exemple de Requête
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html#//apple_ref/doc/uid/TP40002484-SW1
- (City*)findOrCreateCityWithName:(NSString*)cityName
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
// Find the city if it exists, create it if not
NSManagedObject* foundCity = nil;
NSEntityDescription* cityEntity = [NSEntityDescription entityForName:@"City" inManagedObjectContext:context];
NSFetchRequest* cityRequest = [[NSFetchRequest alloc] init];
[cityRequest setEntity:cityEntity];
NSPredicate* cityPredicate = [NSPredicate predicateWithFormat:@"name == %@", cityName];
[cityRequest setPredicate:cityPredicate];
[cityRequest setFetchLimit:1];
NSArray* cities = [context executeFetchRequest:cityRequest error:nil];
if (cities.count == 0)
{
foundCity = [[NSManagedObject alloc] initWithEntity:cityEntity insertIntoManagedObjectContext:context];
[foundCity setValue:cityName forKey:@"name"];
}
else
{
foundCity = [cities objectAtIndex:0];
}
return (City*)foundCity;
}
MagicalRecord
• ActiveRecord pour Objective-C
• Pattern bien connu des programmeurs Ruby
• Utiliser les objets du MDD directement : [Session findAll]
• Un framework «wrapper» pour faciliter votre code
• Requêtes implicites, lecture plus claire
• Plus facile à prendre en main pour débuter en CoreData
• Reste utile même quand vous n’êtes plus débutant pour avoir un code concis
• N’empêche pas de continuer à utiliser les méthodes du framework Apple
- (void)logAllRennesSessions
{
}
NSArray* array = [Session findByAttribute:@"city.name" withValue:@"Rennes" andOrderBy:@"date" ascending:NO];
NSLog(@"Sessions in Rennes: %@", array);
- (void)logAllRennesSessions
{
}
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
// Set predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"];
[request setPredicate:predicate];
// Set sort descriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[request setSortDescriptors:@[sortDescriptor]];
NSArray *array = [moc executeFetchRequest:request error:nil];
NSLog(@"Sessions in Rennes: %@", array);
Exemple de Requête
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc];
Avec MagicalRecord
// Set sort descriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
[request setSortDescriptors:@[sortDescriptor]];
// Set predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"];
[request setPredicate:predicate];
[Session andOrderBy:@"date" ascending:NO];ByAttribute:@"city.name" withValue:@"Rennes"NSArray* array =
NSLog(@"Sessions in Rennes: %@", array);
NSArray *array = [moc executeFetchRequest:request error:nil];
NSLog(@"Sessions in Rennes: %@", array);
find
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
Démo
Comparatif
Nombre de lignes de code CoreData MagicalRecord
Configuration CoreData dans l’AppDelegate 70~90 1
logAllSessions 12 1
emptyGraphObject 17 3
newSessionWithSubject:date:summary:lecturer: 10 6
findOrCreateCityWithName: 24 7
findOrCreatePersonWithFirstName: 25 9
buildFetchedResultsController 24 1
findSimilarSessions 13 2
Total 230~250 65
Avant Après
70% de code
en moins !
Possibilités offertes par
MagicalRecord
• Catégories pour avoir des méthodes de commodité
• Récupérer tous les objets qui suivent un prédicat
• findAll, findAllSortedBy:ascending:, findAllByAttribute:withValue:orderBy:ascending:, findAllSortedBy:ascending:withPredicate:, …
• Compter le nombre d’entités
• countOfEntities, countOfEntitiesWithPredicate:
• Récupérer un seul objet
• findFirst, findFirstWithPredicate:, findFirstWithPredicate:sortedBy:ascending: findFirstByAttribute:withValue:
• Créer et supprimer des entités
• createEntity, deleteEntity, deleteAllMatchingPredicate:, truncateAll, …
• Construire des requêtes
• createFetchRequest, requestAll, requestAllWithPredicate:, requestAllWhere:isEqualTo:, …
• Utiliser les Fetch Results Controllers
• fetchAllSortedBy:ascending:withPredicate:groupBy:delegate:
Possibilités offertes par
MagicalRecord
• Faciliter la gestion des Contextes
• Toutes les méthodes de MR ont une variante avec et sans contexte
• Sans contexte précisé, MR utilise son defaultContext
• Un ManagedObjectContext par défaut, ainsi qu’un contexte par thread
• [NSManagedObjectContext defaultContext], [NSManagedObjectContext contextForCurrentThread]
• Passer un ManagedObject d’un thread à l’autre, d’un contexte à l’autre
• NSManagedObject	
  *objectOnThreadTwo	
  =	
  [objectOnThreadOne	
  inThreadContext];
• NSManagedObject	
  *objectInCtxTwo	
  =	
  [objectInCtxOne	
  inContext:otherContext];
• Création simple d’un contexte fils à la demande
• contextWithParent:, contextThatPushesChangesToDefaultContext
• Gestion des sauvegardes
• En cascade jusqu’au PersistentStore (ex: app en bkg) : saveToPersistentStoreWithCompletion:
• Sur un contexte local via une API avec des blocks : saveWithBlock:completion:, saveInBackgroundWithBlock:…
context
WithParent:
save:
Possibilités offertes par
MagicalRecord
• Simplifier la phase d’initialisation
• Initialisation en une ligne
• [MagicalRecord setupCoreDataStack];
• Très pratique pour les Tests Unitaires
• InMemoryStore : toujours partir sur une base vide, ne pas polluer la base de prod
• [NSBundle bundleForClass:self] pour fonctionner même en phase deTU
• [MagicalRecord setupCoreDataStackWithInMemoryStore];
• Possibilité de créer un NSManagedObjectModel unifié d’après les MOM du bundle
• defaultManagedObjectModel, mergedObjectModelFromMainBundle
• Support d’iCloud
• setupCoreDataStackWithiCloudContainer:localStoreNamed:
• setupCoreDataStackWithiCloudContainer:contentNameKey:localStoreNamed:cloudStorePathComponent:completion:
MagicalRecord avec CocoaPods
pod install
pod update
xcodeproj "MRDemo"
platform :ios, '5.0'
pod "MagicalRecord", "~>2.0"
Podfile
-(BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)options
{
[MagicalRecord setupCoreDataStack];
…
return YES;
}
AppDelegate.m
#ifdef __OBJC__
#define MR_SHORTHAND
#define MR_ENABLE_ACTIVE_RECORD_LOGGING 0
#import "CoreData+MagicalRecord.h"
#endif
Pods-MagicalRecord-prefix.pch
#ifdef __OBJC__
#define MR_SHORTHAND
#import "CoreData+MagicalRecord.h"
#endif
YourApp-Prefix.pch
Références
• CoreData Programming Guide
• https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html
• MagicalRecord
• https://github.com/magicalpanda/MagicalRecord (don’t forget the wiki)
• http://nshipster.com/core-data-libraries-and-utilities/
• CocoaPods
• http://cocoapods.org/ & http://docs.cocoapods.org/
• https://github.com/CocoaPods/Specs (don’t forget the wiki)
• Code source de la démo
• https://github.com/CocoaHeads-Rennes/13-MagicalRecord

Contenu connexe

Tendances

Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
Procédures CLR pour SQL Server : avantages et inconvénients
Procédures CLR pour SQL Server : avantages et inconvénientsProcédures CLR pour SQL Server : avantages et inconvénients
Procédures CLR pour SQL Server : avantages et inconvénientsDenis Voituron
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJean-Pierre Vincent
 
Cours php & Mysql - 2éme partie
Cours php & Mysql - 2éme partieCours php & Mysql - 2éme partie
Cours php & Mysql - 2éme partiekadzaki
 
Introduction à React JS
Introduction à React JSIntroduction à React JS
Introduction à React JSAbdoulaye Dieng
 
Javascript objet : que fait ce code ?
Javascript objet : que fait ce code ?Javascript objet : que fait ce code ?
Javascript objet : que fait ce code ?Ruau Mickael
 
Oxalide Workshop #3 - Elasticearch, an overview
Oxalide Workshop #3 - Elasticearch, an overviewOxalide Workshop #3 - Elasticearch, an overview
Oxalide Workshop #3 - Elasticearch, an overviewLudovic Piot
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptMicrosoft Technet France
 
Découverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanDécouverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanMicrosoft
 
Présentation JavaScript
Présentation JavaScriptPrésentation JavaScript
Présentation JavaScripttarkan_
 
Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?Ruau Mickael
 
Javascript - Tableaux : que fait ce code ?
Javascript - Tableaux : que fait ce code ?Javascript - Tableaux : que fait ce code ?
Javascript - Tableaux : que fait ce code ?Ruau Mickael
 
Réu technodejs
Réu technodejsRéu technodejs
Réu technodejsnaholyr
 
AngularJS et autres techno frontend
AngularJS et autres techno frontendAngularJS et autres techno frontend
AngularJS et autres techno frontendyllieth
 

Tendances (17)

Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Procédures CLR pour SQL Server : avantages et inconvénients
Procédures CLR pour SQL Server : avantages et inconvénientsProcédures CLR pour SQL Server : avantages et inconvénients
Procédures CLR pour SQL Server : avantages et inconvénients
 
Javascript proprement
Javascript proprementJavascript proprement
Javascript proprement
 
Promises Javascript
Promises JavascriptPromises Javascript
Promises Javascript
 
Javascript : fondamentaux et OOP
Javascript : fondamentaux et OOPJavascript : fondamentaux et OOP
Javascript : fondamentaux et OOP
 
Cours php & Mysql - 2éme partie
Cours php & Mysql - 2éme partieCours php & Mysql - 2éme partie
Cours php & Mysql - 2éme partie
 
Cours JavaScript
Cours JavaScriptCours JavaScript
Cours JavaScript
 
Introduction à React JS
Introduction à React JSIntroduction à React JS
Introduction à React JS
 
Javascript objet : que fait ce code ?
Javascript objet : que fait ce code ?Javascript objet : que fait ce code ?
Javascript objet : que fait ce code ?
 
Oxalide Workshop #3 - Elasticearch, an overview
Oxalide Workshop #3 - Elasticearch, an overviewOxalide Workshop #3 - Elasticearch, an overview
Oxalide Workshop #3 - Elasticearch, an overview
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScript
 
Découverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanDécouverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet Spartan
 
Présentation JavaScript
Présentation JavaScriptPrésentation JavaScript
Présentation JavaScript
 
Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?Javascript - Fonctions : que fait ce code ?
Javascript - Fonctions : que fait ce code ?
 
Javascript - Tableaux : que fait ce code ?
Javascript - Tableaux : que fait ce code ?Javascript - Tableaux : que fait ce code ?
Javascript - Tableaux : que fait ce code ?
 
Réu technodejs
Réu technodejsRéu technodejs
Réu technodejs
 
AngularJS et autres techno frontend
AngularJS et autres techno frontendAngularJS et autres techno frontend
AngularJS et autres techno frontend
 

En vedette

CocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeadsRNS
 
CocoaHeads Rennes #14: iOS7 Controllers Transitions
 CocoaHeads Rennes #14: iOS7 Controllers Transitions CocoaHeads Rennes #14: iOS7 Controllers Transitions
CocoaHeads Rennes #14: iOS7 Controllers TransitionsCocoaHeadsRNS
 
CocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeadsRNS
 
La sécurité sur iOS par Arnaud de Bock
La sécurité sur iOS par Arnaud de BockLa sécurité sur iOS par Arnaud de Bock
La sécurité sur iOS par Arnaud de BockNicolas Lourenço
 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPodsCocoaHeads France
 
Programme MFI retour d'expérience
Programme MFI retour d'expérienceProgramme MFI retour d'expérience
Programme MFI retour d'expérienceCocoaHeads France
 
How to communicate with Smart things?
How to communicate with Smart things?How to communicate with Smart things?
How to communicate with Smart things?CocoaHeads France
 

En vedette (19)

CocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPods
 
CocoaHeads Rennes #14: iOS7 Controllers Transitions
 CocoaHeads Rennes #14: iOS7 Controllers Transitions CocoaHeads Rennes #14: iOS7 Controllers Transitions
CocoaHeads Rennes #14: iOS7 Controllers Transitions
 
CocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par Celedev
 
La sécurité sur iOS par Arnaud de Bock
La sécurité sur iOS par Arnaud de BockLa sécurité sur iOS par Arnaud de Bock
La sécurité sur iOS par Arnaud de Bock
 
Design like a developer
Design like a developerDesign like a developer
Design like a developer
 
Super combinators
Super combinatorsSuper combinators
Super combinators
 
Handle the error
Handle the errorHandle the error
Handle the error
 
Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3Quoi de neuf dans iOS 10.3
Quoi de neuf dans iOS 10.3
 
BitTorrent on iOS
BitTorrent on iOSBitTorrent on iOS
BitTorrent on iOS
 
Let's migrate to Swift 3.0
Let's migrate to Swift 3.0Let's migrate to Swift 3.0
Let's migrate to Swift 3.0
 
Project Entourage
Project EntourageProject Entourage
Project Entourage
 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPods
 
CloudKit as a backend
CloudKit as a backendCloudKit as a backend
CloudKit as a backend
 
Présentation de HomeKit
Présentation de HomeKitPrésentation de HomeKit
Présentation de HomeKit
 
What's new in iOS9
What's new in iOS9What's new in iOS9
What's new in iOS9
 
Programme MFI retour d'expérience
Programme MFI retour d'expérienceProgramme MFI retour d'expérience
Programme MFI retour d'expérience
 
SwiftyGPIO
SwiftyGPIOSwiftyGPIO
SwiftyGPIO
 
How to communicate with Smart things?
How to communicate with Smart things?How to communicate with Smart things?
How to communicate with Smart things?
 
IoT Best practices
 IoT Best practices IoT Best practices
IoT Best practices
 

Similaire à CocoaHeads Rennes #13 : Magical Record

OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssOWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssParis Open Source Summit
 
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.MongoDB
 
Devoxx: Tribulation d'un développeur sur le Cloud
Devoxx: Tribulation d'un développeur sur le CloudDevoxx: Tribulation d'un développeur sur le Cloud
Devoxx: Tribulation d'un développeur sur le CloudTugdual Grall
 
Room ou Realm : Quelle base de données pour vos applications Android ?
Room ou Realm : Quelle base de données pour vos applications Android ?Room ou Realm : Quelle base de données pour vos applications Android ?
Room ou Realm : Quelle base de données pour vos applications Android ?Ludovic ROLAND
 
2014 04-09-fr - app dev series - session 4 - indexing
2014 04-09-fr - app dev series - session 4 - indexing2014 04-09-fr - app dev series - session 4 - indexing
2014 04-09-fr - app dev series - session 4 - indexingMongoDB
 
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!Sébastien Levert
 
FORMATION javascript.pdf
FORMATION javascript.pdfFORMATION javascript.pdf
FORMATION javascript.pdfOualidBelbrik
 
Linq et Entity framework
Linq et Entity frameworkLinq et Entity framework
Linq et Entity frameworkDNG Consulting
 
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...Tarik Zakaria Benmerar
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mareValtech
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express jsAbdoulaye Dieng
 
Spring Batch 17-05-2011
Spring Batch 17-05-2011Spring Batch 17-05-2011
Spring Batch 17-05-2011Normandy JUG
 
Jquery - introduction au langage
Jquery - introduction au langageJquery - introduction au langage
Jquery - introduction au langageStrasWeb
 
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big Data
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big DataJournées SQL 2014 - Hive ou la convergence entre datawarehouse et Big Data
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big DataDavid Joubert
 
Spark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystSpark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystMathieu Goeminne
 
SSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLSSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLHervé Leclerc
 

Similaire à CocoaHeads Rennes #13 : Magical Record (20)

OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssOWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
 
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.
2014 03-26-appdevseries-session3-interactingwiththedatabase-fr-phpapp01-rev.
 
Mongo db with C#
Mongo db with C#Mongo db with C#
Mongo db with C#
 
Devoxx: Tribulation d'un développeur sur le Cloud
Devoxx: Tribulation d'un développeur sur le CloudDevoxx: Tribulation d'un développeur sur le Cloud
Devoxx: Tribulation d'un développeur sur le Cloud
 
Room ou Realm : Quelle base de données pour vos applications Android ?
Room ou Realm : Quelle base de données pour vos applications Android ?Room ou Realm : Quelle base de données pour vos applications Android ?
Room ou Realm : Quelle base de données pour vos applications Android ?
 
2014 04-09-fr - app dev series - session 4 - indexing
2014 04-09-fr - app dev series - session 4 - indexing2014 04-09-fr - app dev series - session 4 - indexing
2014 04-09-fr - app dev series - session 4 - indexing
 
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!
Collab365 - Office 365 API & PowerShell : Le meilleur des deux mondes!
 
FORMATION javascript.pdf
FORMATION javascript.pdfFORMATION javascript.pdf
FORMATION javascript.pdf
 
Design Pattern JEE
Design Pattern JEEDesign Pattern JEE
Design Pattern JEE
 
Linq et Entity framework
Linq et Entity frameworkLinq et Entity framework
Linq et Entity framework
 
JADE Framework
JADE FrameworkJADE Framework
JADE Framework
 
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...
Design patterns et Design Emergeant - Micro Days - Modern Software Developmen...
 
Introduction à node.js
Introduction à node.js Introduction à node.js
Introduction à node.js
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express js
 
Spring Batch 17-05-2011
Spring Batch 17-05-2011Spring Batch 17-05-2011
Spring Batch 17-05-2011
 
Jquery - introduction au langage
Jquery - introduction au langageJquery - introduction au langage
Jquery - introduction au langage
 
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big Data
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big DataJournées SQL 2014 - Hive ou la convergence entre datawarehouse et Big Data
Journées SQL 2014 - Hive ou la convergence entre datawarehouse et Big Data
 
Spark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystSpark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et Catalyst
 
SSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLSSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQL
 

Plus de CocoaHeadsRNS

CocoaHeads Rennes #10 : Mock Objects
CocoaHeads Rennes #10 : Mock ObjectsCocoaHeads Rennes #10 : Mock Objects
CocoaHeads Rennes #10 : Mock ObjectsCocoaHeadsRNS
 
CocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeadsRNS
 
CocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeadsRNS
 
CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeadsRNS
 
CocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeadsRNS
 
CocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeadsRNS
 
Cocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeadsRNS
 
CocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeadsRNS
 
CocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeadsRNS
 
CocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeadsRNS
 

Plus de CocoaHeadsRNS (13)

CocoaHeads Rennes #10 : Mock Objects
CocoaHeads Rennes #10 : Mock ObjectsCocoaHeads Rennes #10 : Mock Objects
CocoaHeads Rennes #10 : Mock Objects
 
CocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : Notifications
 
CocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nuls
 
CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeads Rennes #6
CocoaHeads Rennes #6
 
CocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & Android
 
CocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOS
 
CocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOS
 
Cocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOS
 
CocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOS
 
CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4
 
CocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératif
 
CocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central Dispatch
 
CocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisation
 

CocoaHeads Rennes #13 : Magical Record

  • 1. Simplifiez-vous CoreData Avec MagicalRecord CocoaHeads Rennes #13 Olivier Halligon Septembre 2013
  • 2. CoreData : rappels • Framework Cocoa pour iOS et OSX • Permet de gérer un graphe d’objets et sa persistance • Gestion de relations • Gestion des transactions, d’annulation… • Gestion des futures (faulting) • N’est pas une base de données relationnelle • On peut l’utiliser en InMemory-only • Peut faire persister les données dans une base SQLite mais aussi en XML • On peut l’utiliser comme abstraction d’un WebService (via NSIncrementalStore)
  • 3. Exemple de modèle de données
  • 5. Complexité de CoreData • Beaucoup de classes à prendre en main quand on commence • Dont pour la plupart le rôle semble abstrait de prime abord • Même si ça vient avec la pratique, peu encourageant au début • Beaucoup de lignes de code pour des opérations simples • Une dizaine de lignes rien que pour récupérer un objet dans notre graphe • Du coup répétitif pour des actions fréquentes • Nécessité d’utiliser des NSString pour décrire les noms d’entités à récupérer • Pas d’autocomplétion, pas de vérification à la compilation • Nécessité de transtyper (caster) les résultats
  • 6. Exemple de Requête https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html#//apple_ref/doc/uid/TP40002484-SW1 - (void)logAllRennesSessions { NSManagedObjectContext *moc = [self managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc]; NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:entityDescription]; // Set sort descriptor NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]; [request setSortDescriptors:@[sortDescriptor]]; // Set predicate NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"]; [request setPredicate:predicate]; NSArray *array = [moc executeFetchRequest:request error:nil]; if (array == nil) { NSLog(@"Some error occured"); } else { NSLog(@"Sessions in Rennes: %@", array); } }
  • 7. Exemple de Requête https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html#//apple_ref/doc/uid/TP40002484-SW1 - (City*)findOrCreateCityWithName:(NSString*)cityName { NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; // Find the city if it exists, create it if not NSManagedObject* foundCity = nil; NSEntityDescription* cityEntity = [NSEntityDescription entityForName:@"City" inManagedObjectContext:context]; NSFetchRequest* cityRequest = [[NSFetchRequest alloc] init]; [cityRequest setEntity:cityEntity]; NSPredicate* cityPredicate = [NSPredicate predicateWithFormat:@"name == %@", cityName]; [cityRequest setPredicate:cityPredicate]; [cityRequest setFetchLimit:1]; NSArray* cities = [context executeFetchRequest:cityRequest error:nil]; if (cities.count == 0) { foundCity = [[NSManagedObject alloc] initWithEntity:cityEntity insertIntoManagedObjectContext:context]; [foundCity setValue:cityName forKey:@"name"]; } else { foundCity = [cities objectAtIndex:0]; } return (City*)foundCity; }
  • 8. MagicalRecord • ActiveRecord pour Objective-C • Pattern bien connu des programmeurs Ruby • Utiliser les objets du MDD directement : [Session findAll] • Un framework «wrapper» pour faciliter votre code • Requêtes implicites, lecture plus claire • Plus facile à prendre en main pour débuter en CoreData • Reste utile même quand vous n’êtes plus débutant pour avoir un code concis • N’empêche pas de continuer à utiliser les méthodes du framework Apple
  • 9. - (void)logAllRennesSessions { } NSArray* array = [Session findByAttribute:@"city.name" withValue:@"Rennes" andOrderBy:@"date" ascending:NO]; NSLog(@"Sessions in Rennes: %@", array); - (void)logAllRennesSessions { } NSManagedObjectContext *moc = [self managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc]; NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:entityDescription]; // Set predicate NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"]; [request setPredicate:predicate]; // Set sort descriptor NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]; [request setSortDescriptors:@[sortDescriptor]]; NSArray *array = [moc executeFetchRequest:request error:nil]; NSLog(@"Sessions in Rennes: %@", array); Exemple de Requête NSManagedObjectContext *moc = [self managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Session" inManagedObjectContext:moc]; Avec MagicalRecord // Set sort descriptor NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]; [request setSortDescriptors:@[sortDescriptor]]; // Set predicate NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city.name == %@", @"Rennes"]; [request setPredicate:predicate]; [Session andOrderBy:@"date" ascending:NO];ByAttribute:@"city.name" withValue:@"Rennes"NSArray* array = NSLog(@"Sessions in Rennes: %@", array); NSArray *array = [moc executeFetchRequest:request error:nil]; NSLog(@"Sessions in Rennes: %@", array); find NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:entityDescription];
  • 10. Démo
  • 11. Comparatif Nombre de lignes de code CoreData MagicalRecord Configuration CoreData dans l’AppDelegate 70~90 1 logAllSessions 12 1 emptyGraphObject 17 3 newSessionWithSubject:date:summary:lecturer: 10 6 findOrCreateCityWithName: 24 7 findOrCreatePersonWithFirstName: 25 9 buildFetchedResultsController 24 1 findSimilarSessions 13 2 Total 230~250 65 Avant Après 70% de code en moins !
  • 12. Possibilités offertes par MagicalRecord • Catégories pour avoir des méthodes de commodité • Récupérer tous les objets qui suivent un prédicat • findAll, findAllSortedBy:ascending:, findAllByAttribute:withValue:orderBy:ascending:, findAllSortedBy:ascending:withPredicate:, … • Compter le nombre d’entités • countOfEntities, countOfEntitiesWithPredicate: • Récupérer un seul objet • findFirst, findFirstWithPredicate:, findFirstWithPredicate:sortedBy:ascending: findFirstByAttribute:withValue: • Créer et supprimer des entités • createEntity, deleteEntity, deleteAllMatchingPredicate:, truncateAll, … • Construire des requêtes • createFetchRequest, requestAll, requestAllWithPredicate:, requestAllWhere:isEqualTo:, … • Utiliser les Fetch Results Controllers • fetchAllSortedBy:ascending:withPredicate:groupBy:delegate:
  • 13. Possibilités offertes par MagicalRecord • Faciliter la gestion des Contextes • Toutes les méthodes de MR ont une variante avec et sans contexte • Sans contexte précisé, MR utilise son defaultContext • Un ManagedObjectContext par défaut, ainsi qu’un contexte par thread • [NSManagedObjectContext defaultContext], [NSManagedObjectContext contextForCurrentThread] • Passer un ManagedObject d’un thread à l’autre, d’un contexte à l’autre • NSManagedObject  *objectOnThreadTwo  =  [objectOnThreadOne  inThreadContext]; • NSManagedObject  *objectInCtxTwo  =  [objectInCtxOne  inContext:otherContext]; • Création simple d’un contexte fils à la demande • contextWithParent:, contextThatPushesChangesToDefaultContext • Gestion des sauvegardes • En cascade jusqu’au PersistentStore (ex: app en bkg) : saveToPersistentStoreWithCompletion: • Sur un contexte local via une API avec des blocks : saveWithBlock:completion:, saveInBackgroundWithBlock:… context WithParent: save:
  • 14. Possibilités offertes par MagicalRecord • Simplifier la phase d’initialisation • Initialisation en une ligne • [MagicalRecord setupCoreDataStack]; • Très pratique pour les Tests Unitaires • InMemoryStore : toujours partir sur une base vide, ne pas polluer la base de prod • [NSBundle bundleForClass:self] pour fonctionner même en phase deTU • [MagicalRecord setupCoreDataStackWithInMemoryStore]; • Possibilité de créer un NSManagedObjectModel unifié d’après les MOM du bundle • defaultManagedObjectModel, mergedObjectModelFromMainBundle • Support d’iCloud • setupCoreDataStackWithiCloudContainer:localStoreNamed: • setupCoreDataStackWithiCloudContainer:contentNameKey:localStoreNamed:cloudStorePathComponent:completion:
  • 15. MagicalRecord avec CocoaPods pod install pod update xcodeproj "MRDemo" platform :ios, '5.0' pod "MagicalRecord", "~>2.0" Podfile -(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)options { [MagicalRecord setupCoreDataStack]; … return YES; } AppDelegate.m #ifdef __OBJC__ #define MR_SHORTHAND #define MR_ENABLE_ACTIVE_RECORD_LOGGING 0 #import "CoreData+MagicalRecord.h" #endif Pods-MagicalRecord-prefix.pch #ifdef __OBJC__ #define MR_SHORTHAND #import "CoreData+MagicalRecord.h" #endif YourApp-Prefix.pch
  • 16. Références • CoreData Programming Guide • https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html • MagicalRecord • https://github.com/magicalpanda/MagicalRecord (don’t forget the wiki) • http://nshipster.com/core-data-libraries-and-utilities/ • CocoaPods • http://cocoapods.org/ & http://docs.cocoapods.org/ • https://github.com/CocoaPods/Specs (don’t forget the wiki) • Code source de la démo • https://github.com/CocoaHeads-Rennes/13-MagicalRecord