Your SlideShare is downloading. ×
0
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

CocoaHeads Rennes #13 : Magical Record

3,570

Published on

CoreData vous tente mais vous fait peur ? Vous trouvez le framework un peu dur à prendre en main ? Ou vous en avez marre d’écrire autant de ligne à chaque fois juste pour faire une simple récupération …

CoreData vous tente mais vous fait peur ? Vous trouvez le framework un peu dur à prendre en main ? Ou vous en avez marre d’écrire autant de ligne à chaque fois juste pour faire une simple récupération de vos données ?

Olivier Halligon (développeur de FoodReporter) vous offrira une découverte de MagicalRecord, le framework qui va drastiquement simplifier votre code CoreData, en apportant le Design Pattern ActiveRecord (comme utilisé en Ruby) sur Objective-C.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
3,570
On Slideshare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 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
  • 4. Complexité de CoreData NSAtomic StoreNSPersistent Store NSManagedObjectModel NSFetchResult Controller NSAttribute Description NSManagedObjectID NSEntityMapping NSManagedObject NSFetch Request NSManaged ObjectContext NSEntityDescription NSIncremental Store NSPersistentStoreCoordinator
  • 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

×