Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ICYMI: Core Data at CMD+R 2014
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Kyle Fuller
October 22, 2014
Technology
350
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ICYMI: Core Data at CMD+R 2014
https://github.com/QueryKit
Kyle Fuller
October 22, 2014
More Decks by Kyle Fuller
See All by Kyle Fuller
Design APIs and deliver what you promised
kylef
0
150
Preparing for the future of API Description Languages
kylef
0
130
Resilient API Design
kylef
1
370
Building a Swift Web API and Application Together
kylef
2
2.2k
Testing without Xcode - CMD+U 2016
kylef
0
300
End-to-end: Building a Web Service in Swift (MCE 2016)
kylef
2
510
Designing APIs for Humans - Write the Docs 2016
kylef
0
370
Embracing Change - MBLTDev 2015
kylef
3
720
Practical Declarative Programming (360 iDev 2015)
kylef
3
570
Other Decks in Technology
See All in Technology
プラットフォームを「作る」、 チームに「入り込む」
sansantech
PRO
0
360
AI Native Platform Engineering 〜PlatformとAgileで“作る速さ”を“価値”へ〜
uya116
0
440
spanner-autoscalerに学ぶ CRD設計パターン 〜自動化と緊急時対応を両立する Kubernetesコントローラーの作り方〜
tkuchiki
0
200
なぜ「決定性」が 決定的に重要なのか? Durable Execution 基盤の数理的理解 #serverlessjp / ServerlessDays Tokyo 2026
ytaka23
4
1.4k
AIに会社の文脈を理解させる技術~上流工程・非エンジニアにも広げるハーネスエンジニアリング実践~
ochtum
0
190
AIは推し活である。
kurazuuuuuu
2
1k
AI感のないAWS構成図をAIエージェントに描かせたい!
sagochiko
2
480
Azure Copilot Resiliency Agentをいろいろ試してみる
tomokusaba
0
130
[Kiro Meetup #7] Kiro Crew Dive Deep
konippi
0
410
Terraformを用いたJamf Pro構成のIaC, GitOps化への挑戦
yukun
0
110
覗いてみよう 関数型ビジュアル言語×2Dグラフィックスの世界
yohyamasaki
0
150
20260929_AmazonGuardDutyの検出通知メールにAWS DevOpsAgentの調査結果を追加する
yhana
1
360
Featured
See All Featured
Done Done
chrislema
187
17k
Optimizing for Happiness
mojombo
378
71k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Scaling GitHub
holman
464
140k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
930
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
550
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
310
Designing Powerful Visuals for Engaging Learning
tmiket
1
580
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
The Limits of Empathy - UXLibs8
cassininazir
1
690
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