ICYMI: Core Data at CMD+R 2014

D200a17dd269fd4001bacb11662dab4b?s=47 Kyle Fuller
October 22, 2014

ICYMI: Core Data at CMD+R 2014

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

October 22, 2014
Tweet

Transcript

  1. ICYMI:&Core&Data !@kylefuller

  2. !@kylefuller

  3. None
  4. None
  5. CoreData

  6. What%is%Core%Data?

  7. Framework)for)persistence)and) object)graph)management

  8. Database

  9. SQL$Wrapper$or$ORM

  10. None
  11. Change'No*fica*on

  12. Key$Value$Observing

  13. RACObserve(person, "name").subscribeNext { name in println("Person's name did change to

    \(name).") }
  14. NSManagedObjectContextObjectsDidChangeNo5fica5on

  15. NSDeletedObjectsKey

  16. NSInsertedObjectsKey

  17. NSUpdatedObjectsKey

  18. Valida&on

  19. None
  20. var name = "Kyle" var error:NSError? if person.validateValue( AutoreleasingUnsafeMutablePointer(&name), forKey:"name",

    error:&error) { println("\(name) is a valid name.") }
  21. Properga(on

  22. None
  23. Migra&ons

  24. NSMigratePersistentStoresAutoma1callyOp1on

  25. class Person : NSManagedObject {¬ var name:String + var birthdate:NSDate?

    }
  26. Components

  27. NSManagedObject

  28. class Person : NSManagedObject { var name:String }

  29. @objc(Person) class Person : NSManagedObject { @NSManaged var name:String }

  30. None
  31. Mogenerator

  32. $ brew install mogenerator

  33. $ mogenerator --model=Model.xcdatamodeld --machine-dir=Model/Machine --human-dir=Model

  34. ├── Machine │ ├── _Organisation.swift │ └── _Person.swift ├── Organisation.swift

    └── Person.swift
  35. let person:NSManagedObject = ...; person.valueForKey("name")

  36. NSManagedObjectContext

  37. None
  38. NSManagedObjectContext(concurrencyType)

  39. enum NSManagedObjectContextConcurrencyType : UInt { case ConfinementConcurrencyType case PrivateQueueConcurrencyType case

    MainQueueConcurrencyType }
  40. context.performBlock { }

  41. context.performBlockAndWait { }

  42. NSPersistentStoreCoordinator

  43. NSPersistentStore

  44. NSSQLiteStoreType

  45. let options = [ NSPersistentStoreUbiquitousContentNameKey: "Posts" ]

  46. NSInMemoryStoreType

  47. Stack

  48. None
  49. None
  50. Performance

  51. None
  52. None
  53. None
  54. None
  55. Locking

  56. Write&Ahead&Locking

  57. None
  58. Boilerplate

  59. KFData/Store

  60. None
  61. Querying

  62. NSFetchRequest • predicate • sortDescriptors

  63. NSFetchRequest • predicate • sortDescriptors • fetchLimit • fetchOffset •

    fetchBatchSize • ...
  64. NSSortDescriptor NSSortDescriptor(key: "title", ascending: true)

  65. NSPredicate NSPredicate(format: "author == 'Kyle'")

  66. Every&Ar(cle

  67. Every&Ar(cle • Ordered&by&Title • Wri.en&Kyle

  68. let fetchRequest = NSFetchRequest(entityName: "Article")

  69. fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]

  70. fetchRequest.predicate = NSPredicate(format: "author == 'Kyle'")

  71. var error:NSError? let articles = managedObjectContext.executeFetchRequest(fetchRequest, error: &error)

  72. let fetchRequest = NSFetchRequest(entityName: "Article") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending:

    true)] fetchRequest.predicate = NSPredicate(format: "author == 'Kyle'") var error:NSError? let articles = managedObjectContext.executeFetchRequest(fetchRequest, error: &error)
  73. let fetchRequest = NSFetchRequest(entityName: "Article") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending:

    true)] fetchRequest.predicate = NSPredicate(format: "author == 'Kyle'") var error:NSError? let articles = managedObjectContext.executeFetchRequest(fetchRequest, error: &error) if let error = error { println("Failed to execute fetch request: \(error)") } else { println("Success") }
  74. "Article" "title" "author == 'Kyle'" .

  75. None
  76. let result = Article.queryset(context) .filter(Article.attributes.author == "Kyle") .orderBy(Article.attributes.title)

  77. None
  78. Asyncronous)Fetching

  79. NSAsyncronousFetchRequest

  80. let request = NSAsyncronousFetchRequest(fetchRequest:fetchRequest) { result in } var error:NSError?

    managedObjectContext.executeRequest(request, &error)
  81. Fetched'Results'Controller

  82. // MARK: NSFetchedResultsControllerDelegate func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.reloadData() } //

    MARK: UITableViewDataSource func numberOfSectionsInTableView(tableView: UITableView) -> Int { return fetchedResultsController.sections?.count } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let sectionInfo = fetchedResultsController.sections[section] as NSFetchedResultsSectionInfo return sectionInfo.numberOfObjects() } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { return cell from managed object }
  83. func controllerWillChangeContent(controller: NSFetchedResultsController) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeObject

    anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { // Insert, reload or remove rows } func controllerDidChangeContent(controller: NSFetchedResultsController) { tableView.endUpdates() }
  84. Boilerplate

  85. - (instancetype)initWithTableView:(UITableView *)tableView fetchedResultsController:(NSFetchedResultsController *)fetchedResultsController { NSParameterAssert(tableView != nil); NSParameterAssert(fetchedResultsController

    != nil); if (self = [super init]) { _tableView = tableView; tableView.dataSource = self; _fetchedResultsController = fetchedResultsController; _fetchedResultsController.delegate = self; } return self; } - (instancetype)initWithTableView:(UITableView *)tableView managedObjectContext:(NSManagedObjectContext *)managedObjectContext fetchRequest:(NSFetchRequest *)fetchRequest sectionNameKeyPath:(NSString *)sectionNameKeyPath cacheName:(NSString *)cacheName { NSParameterAssert(managedObjectContext != nil); NSParameterAssert(fetchRequest != nil); NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionNameKeyPath cacheName:cacheName]; return [self initWithTableView:tableView fetchedResultsController:fetchedResultsController]; } - (NSManagedObjectContext *)managedObjectContext { return [_fetchedResultsController managedObjectContext]; } - (NSFetchRequest *)fetchRequest { return [_fetchedResultsController fetchRequest]; } - (BOOL)performFetch:(NSError **)error { BOOL result = [self.fetchedResultsController performFetch:error]; [self.tableView reloadData]; return result; } #pragma mark - - (id <NSFetchedResultsSectionInfo>)sectionInfoForSection:(NSUInteger)section { return self.fetchedResultsController.sections[section]; } - (id <NSObject>)objectAtIndexPath:(NSIndexPath *)indexPath { return [self sectionInfoForSection:indexPath.section].objects[indexPath.row]; } #pragma mark - NSFetchedResultsControllerDelegate - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { [self.tableView beginUpdates]; } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:sectionIndex]; switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: case NSFetchedResultsChangeMove: break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: { [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; } #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSUInteger count = [self.fetchedResultsController.sections count]; return (NSInteger)count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [self sectionInfoForSection:section]; return (NSInteger)sectionInfo.numberOfObjects; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if (self.cellForManagedObject == nil) { NSString *reason = [NSString stringWithFormat:@"%@: You must override %@ or set %@", NSStringFromClass([self class]), NSStringFromSelector(@selector(tableView:cellForRowAtIndexPath:)), NSStringFromSelector(@selector(cellForManagedObject))]; @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:reason userInfo:nil]; } NSManagedObject *managedObject = [self objectAtIndexPath:indexPath]; return self.cellForManagedObject(tableView, indexPath, managedObject); } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return [[self sectionInfoForSection:section] name]; } - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { return nil; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { switch (editingStyle) { case UITableViewCellEditingStyleDelete: { NSManagedObject *managedObject = [self objectAtIndexPath:indexPath]; [self.managedObjectContext deleteObject:managedObject]; NSError *error; if ([self.managedObjectContext save:&error] == NO) { NSLog(@"%@: Failed to save managed object context after deleting %@", NSStringFromClass([self class]), error); } break; } case UITableViewCellEditingStyleInsert: break; case UITableViewCellEditingStyleNone: break; } }
  86. UIKit&Data&Sources • Kyle&Fuller:&KFData/UI • Ash&Furrow:&UICollec8onView+NSFetchedResultsController • Sam&Soffes:&SSDataKit

  87. Debugging

  88. let viewController = CCLEntityListViewController(context) presentViewController(viewController, animated:true)

  89. None
  90. !@kylefuller