$30 off During Our Annual Pro Sale. View Details »

ICYMI: Core Data at CMD+R 2014

Kyle Fuller
October 22, 2014

ICYMI: Core Data at CMD+R 2014

Kyle Fuller

October 22, 2014
Tweet

More Decks by Kyle Fuller

Other Decks in Technology

Transcript

  1. ICYMI:&Core&Data
    !@kylefuller

    View Slide

  2. !@kylefuller

    View Slide

  3. View Slide

  4. View Slide

  5. CoreData

    View Slide

  6. What%is%Core%Data?

    View Slide

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

    View Slide

  8. Database

    View Slide

  9. SQL$Wrapper$or$ORM

    View Slide

  10. View Slide

  11. Change'No*fica*on

    View Slide

  12. Key$Value$Observing

    View Slide

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

    View Slide

  14. NSManagedObjectContextObjectsDidChangeNo5fica5on

    View Slide

  15. NSDeletedObjectsKey

    View Slide

  16. NSInsertedObjectsKey

    View Slide

  17. NSUpdatedObjectsKey

    View Slide

  18. Valida&on

    View Slide

  19. View Slide

  20. var name = "Kyle"
    var error:NSError?
    if person.validateValue(
    AutoreleasingUnsafeMutablePointer(&name),
    forKey:"name",
    error:&error)
    {
    println("\(name) is a valid name.")
    }

    View Slide

  21. Properga(on

    View Slide

  22. View Slide

  23. Migra&ons

    View Slide

  24. NSMigratePersistentStoresAutoma1callyOp1on

    View Slide

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

    View Slide

  26. Components

    View Slide

  27. NSManagedObject

    View Slide

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

    View Slide

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

    View Slide

  30. View Slide

  31. Mogenerator

    View Slide

  32. $ brew install mogenerator

    View Slide

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

    View Slide

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

    View Slide

  35. let person:NSManagedObject = ...;
    person.valueForKey("name")

    View Slide

  36. NSManagedObjectContext

    View Slide

  37. View Slide

  38. NSManagedObjectContext(concurrencyType)

    View Slide

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

    View Slide

  40. context.performBlock {
    }

    View Slide

  41. context.performBlockAndWait {
    }

    View Slide

  42. NSPersistentStoreCoordinator

    View Slide

  43. NSPersistentStore

    View Slide

  44. NSSQLiteStoreType

    View Slide

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

    View Slide

  46. NSInMemoryStoreType

    View Slide

  47. Stack

    View Slide

  48. View Slide

  49. View Slide

  50. Performance

    View Slide

  51. View Slide

  52. View Slide

  53. View Slide

  54. View Slide

  55. Locking

    View Slide

  56. Write&Ahead&Locking

    View Slide

  57. View Slide

  58. Boilerplate

    View Slide

  59. KFData/Store

    View Slide

  60. View Slide

  61. Querying

    View Slide

  62. NSFetchRequest
    • predicate
    • sortDescriptors

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. Every&Ar(cle

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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)

    View Slide

  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")
    }

    View Slide

  74. "Article"
    "title"
    "author == 'Kyle'"
    .

    View Slide

  75. View Slide

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

    View Slide

  77. View Slide

  78. Asyncronous)Fetching

    View Slide

  79. NSAsyncronousFetchRequest

    View Slide

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

    View Slide

  81. Fetched'Results'Controller

    View Slide

  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
    }

    View Slide

  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()
    }

    View Slide

  84. Boilerplate

    View Slide

  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 )sectionInfoForSection:(NSUInteger)section {
    return self.fetchedResultsController.sections[section];
    }
    - (id )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 )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 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;
    }
    }

    View Slide

  86. UIKit&Data&Sources
    • Kyle&Fuller:&KFData/UI
    • Ash&Furrow:&UICollec8onView+NSFetchedResultsController
    • Sam&Soffes:&SSDataKit

    View Slide

  87. Debugging

    View Slide

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

    View Slide

  89. View Slide

  90. !@kylefuller

    View Slide