Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
ICYMI: Core Data at CMD+R 2014
Kyle Fuller
October 22, 2014
Technology
3
250
ICYMI: Core Data at CMD+R 2014
https://github.com/QueryKit
Kyle Fuller
October 22, 2014
Tweet
Share
More Decks by Kyle Fuller
See All by Kyle Fuller
kylef
0
9
kylef
0
31
kylef
1
200
kylef
2
1.2k
kylef
0
150
kylef
2
380
kylef
0
110
kylef
3
460
kylef
3
220
Other Decks in Technology
See All in Technology
eayedi
2
150
nitya
0
280
miyake
1
430
futo23
1
320
kahara33
0
110
xecus
0
190
tnmt
2
230
tosh2230
3
280
minma
0
120
azara
1
890
yoku0825
PRO
3
120
go5paopao
4
310
Featured
See All Featured
pedronauck
652
110k
carmenhchung
31
1.5k
morganepeng
93
14k
philnash
9
580
hannesfritz
28
950
brianwarren
82
4.7k
zakiwarfel
88
3.4k
geoffreycrofte
21
920
marktimemedia
7
400
malarkey
119
16k
imathis
479
150k
samlambert
237
10k
Transcript
ICYMI:&Core&Data !@kylefuller
!@kylefuller
None
None
CoreData
What%is%Core%Data?
Framework)for)persistence)and) object)graph)management
Database
SQL$Wrapper$or$ORM
None
Change'No*fica*on
Key$Value$Observing
RACObserve(person, "name").subscribeNext { name in println("Person's name did change to
\(name).") }
NSManagedObjectContextObjectsDidChangeNo5fica5on
NSDeletedObjectsKey
NSInsertedObjectsKey
NSUpdatedObjectsKey
Valida&on
None
var name = "Kyle" var error:NSError? if person.validateValue( AutoreleasingUnsafeMutablePointer(&name), forKey:"name",
error:&error) { println("\(name) is a valid name.") }
Properga(on
None
Migra&ons
NSMigratePersistentStoresAutoma1callyOp1on
class Person : NSManagedObject {¬ var name:String + var birthdate:NSDate?
}
Components
NSManagedObject
class Person : NSManagedObject { var name:String }
@objc(Person) class Person : NSManagedObject { @NSManaged var name:String }
None
Mogenerator
$ brew install mogenerator
$ mogenerator --model=Model.xcdatamodeld --machine-dir=Model/Machine --human-dir=Model
├── Machine │ ├── _Organisation.swift │ └── _Person.swift ├── Organisation.swift
└── Person.swift
let person:NSManagedObject = ...; person.valueForKey("name")
NSManagedObjectContext
None
NSManagedObjectContext(concurrencyType)
enum NSManagedObjectContextConcurrencyType : UInt { case ConfinementConcurrencyType case PrivateQueueConcurrencyType case
MainQueueConcurrencyType }
context.performBlock { }
context.performBlockAndWait { }
NSPersistentStoreCoordinator
NSPersistentStore
NSSQLiteStoreType
let options = [ NSPersistentStoreUbiquitousContentNameKey: "Posts" ]
NSInMemoryStoreType
Stack
None
None
Performance
None
None
None
None
Locking
Write&Ahead&Locking
None
Boilerplate
KFData/Store
None
Querying
NSFetchRequest • predicate • sortDescriptors
NSFetchRequest • predicate • sortDescriptors • fetchLimit • fetchOffset •
fetchBatchSize • ...
NSSortDescriptor NSSortDescriptor(key: "title", ascending: true)
NSPredicate NSPredicate(format: "author == 'Kyle'")
Every&Ar(cle
Every&Ar(cle • Ordered&by&Title • Wri.en&Kyle
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)
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)
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") }
"Article" "title" "author == 'Kyle'" .
None
let result = Article.queryset(context) .filter(Article.attributes.author == "Kyle") .orderBy(Article.attributes.title)
None
Asyncronous)Fetching
NSAsyncronousFetchRequest
let request = NSAsyncronousFetchRequest(fetchRequest:fetchRequest) { result in } var error:NSError?
managedObjectContext.executeRequest(request, &error)
Fetched'Results'Controller
// 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 }
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() }
Boilerplate
- (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; } }
UIKit&Data&Sources • Kyle&Fuller:&KFData/UI • Ash&Furrow:&UICollec8onView+NSFetchedResultsController • Sam&Soffes:&SSDataKit
Debugging
let viewController = CCLEntityListViewController(context) presentViewController(viewController, animated:true)
None
!@kylefuller