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
Kyle Fuller
October 22, 2014
Technology
360
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
160
Preparing for the future of API Description Languages
kylef
0
140
Resilient API Design
kylef
1
380
Building a Swift Web API and Application Together
kylef
2
2.2k
Testing without Xcode - CMD+U 2016
kylef
0
310
End-to-end: Building a Web Service in Swift (MCE 2016)
kylef
2
520
Designing APIs for Humans - Write the Docs 2016
kylef
0
380
Embracing Change - MBLTDev 2015
kylef
3
730
Practical Declarative Programming (360 iDev 2015)
kylef
3
580
Other Decks in Technology
See All in Technology
ストレスなくAIと付き合いたい!こんなときどうしてる?
namiki64
4
680
局所最適は悪ではない。壊れているのは指標です。量と質を同時に見る先行指標の設計
recruitengineers
PRO
2
1.1k
小規模OSSモデルは サイバーセキュリティ業務に どこまで使えるか
bbrbbq
0
280
その Valkey 使いこなしていますか?
onk
PRO
5
2k
企画を Software Factory-ready にする——開発が高速になったとき、PdMの仕事はどう変わったか
yachibit
1
250
LLM Content Moderationを支える評価・改善ループの実践
suikabar
2
330
Draft AIエージェントの トークン消費を最小化する 8つの原則
kinopeee
3
1.5k
ドメインエキスパートは いかにして AI を使って プロダクト開発をするか
tatsuyashiraishi
1
150
Temporal 最高!でも改めて「日付」について調べたら人類の負債すぎる件
riyaamemiya
0
230
What Is JetBrains Air
x5gtrn
PRO
0
160
CSS2026:OWS研究会・招待講演「世界観を、実装する」
atsush1_sada
2
280
Claude Code on Bedrock で統制をかける小ネタ集/claude-code-bedrock-governance-tips
emiki
1
11k
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
4k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
360
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
540
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
740
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Building AI with AI
inesmontani
PRO
1
1.3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
580
Color Theory Basics | Prateek | Gurzu
gurzu
1
490
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
1k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
420
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