SlideShare uma empresa Scribd logo
1 de 85
Baixar para ler offline
Diego Freniche / http://www.freniche.com
Core Data in 547 easy steps slide 1/373
Diego Freniche / @dfreniche / http://www.freniche.com
Core Data Workshop
Diego Freniche: programmer & teacher
• @dfreniche

• Freelance Mobile developer: iOS/Android/BB10/
webOS/...

• In a former life Java Certifications Collector: SCJP
1.5, SCJP 1.6, SCWCD 1.5, SCBCD 1.3

• Some languages: BASIC, PASCAL, C, C++, Delphi,
COBOL, Clipper, Visual Basic, Java, JavaScript,
Objective-C
Hello, World!
Diego Freniche / http://www.freniche.com
Core Data: developer’s first impression
Diego Freniche / http://www.freniche.com
Diego Freniche / @dfreniche / http://www.freniche.com
Core Data Hello World!
Diego Freniche / @dfreniche / http://www.freniche.com
That’s easy peasy
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Apple’s code
!
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
!#pragma mark - Core Data stack
!// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
!// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Test" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
!// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Test.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
!#pragma mark - Application's Documents directory
!// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
Diego Freniche / @dfreniche / http://www.freniche.com
Corollary
• Never, ever use the Core Data checkbox

• BIG design flaws:

• Core Data Stack coupled to AppDelegate: 

• can’t reuse in other projects

• separations of concerns, anyone?

• ugly! and just ONE Core Data Stack

• They don’t even use a custom class
Diego Freniche / @dfreniche / http://www.freniche.com
What is Core Data?
• Poll

• A Framework. Must be important: its name starts with “Core”

• An ORM

• The model of your App

• Technology to help you that has a steep learning curve
Diego Freniche / @dfreniche / http://www.freniche.com
One of the problems
• Objet - Relational impedance

• SQL: 70s/80s

• OOP: 80s-
Diego Freniche / @dfreniche / http://www.freniche.com
Exhibit 1: composition
id name idCard
Person
+name: String
+idCard: idCard
+bankAccout: bankAccount
idCard
+number: int
+letter: char
+checkLetter()
VARCHAR ¿?
Diego Freniche / @dfreniche / http://www.freniche.com
Employee
+empNumber: int
Person
+name: String
+idCard: idCard
Exhibit 2: inheritance
Hyena
Politician
+moneyTaken: double
Diego Freniche / @dfreniche / http://www.freniche.com
Exhibit 3: collection modelling
Person
+name: String
+bills: Bill[]
Bill
0..*1
http://en.wikipedia.org/wiki/First_normal_form
Diego Freniche / @dfreniche / http://www.freniche.com
Relational World
• tables

• cartesian products

• rows/ columns

• normal forms
• Objects

• object collections

• composition

• inheritance
OO World
Diego Freniche / @dfreniche / http://www.freniche.com
The solution: ORM
• Object Relational Mapper

• Hibernate (Java, .Net)

• Core Data (Cocoa)
• Core Data is our model
• can persist our objects
in several ways
Diego Freniche / @dfreniche / http://www.freniche.com
Which problems will Core Data help me solve?
• Persist my data

• Cache online data

• to speed up things

• to show something to the user when (if) there’s no Internet connection

• Navigate the object graph:

• [([Company allEmployees][0]).boss name];

• Maintain ViewControllers in sync
Diego Freniche / @dfreniche / http://www.freniche.com
Don’t fight the Frameworks!
• Yes! You need to learn them!

• Everything well thought-out to work with Core Data

• Working with databases without Core Data?

• not so much fun!

• reinvent the wheel

• this is not JavaScript-Land!
Diego Freniche / @dfreniche / http://www.freniche.com
Core Data terms
• Entity
• an entity in our model == Object in memory == row in table

• Attribute
• Relationship
• Object graph
http://ogre.berniecode.com/ogre_white_paper
Diego Freniche / @dfreniche / http://www.freniche.com
To get the most out of Core Data
• You need to understand:

• KVC, KVO

• ARC, memory management

• delegate & MVC patterns

• that singletons are evil (more or less)
Diego Freniche / @dfreniche / http://www.freniche.com
The Core Data Stack
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Context
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Diego Freniche / @dfreniche / http://www.freniche.com
Our Model
NSManagedObject
NSManagedObject
NSManagedObject
NSManagedObject
Persisted
NSManagedObjectContext
NSObject
In memory only
Diego Freniche / @dfreniche / http://www.freniche.com
Move away from NSObject!
!
@interface	
  MyClass	
  :	
  NSObject	
  
!
@end	
  	
  
!
@interface	
  MyClass	
  :	
  NSManagedObject	
  
!
@end	
  
Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Context: MOC
• Managed Object Context: in-memory space where CD manages all our
model’s objects.

• All CRUD is done against a MOC. We persist data using [context save:]

• Our model’s objects are Managed Objects.

• The MOC needs a Persistent Store Coordinator to save the object graph in
persistent store.
Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Model
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Model
• Maps our model objects into database tables.

• Objects == NSManagedObject

• Classes == NSEntityDescription

• We describe our App entities inside a MOM

• stored inside .xcdatamodeld files in Xcode. Compiles into .momd

• graphic editor / class generator (dumb)
Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Model
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Diego Freniche / @dfreniche / http://www.freniche.com
Persistent Store Coordinador
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Makes the mapping between our App’s
objects and the physical storage inside
the Persistent Object Store.
99% time we’ll work with ONE Object
Store, but it’s possible use more than
one. For example, a sqlite DB with
recipes and another DB with notes,
stars, etc. Coordinator: single façade
to work with different Stores.

!
A managed object context can then
create an object graph based on the
union of all the data stores the
coordinator covers
Persistent Object Store
Diego Freniche / http://www.freniche.com
Persistent Store Coordinador
Called Coordinator for a reason:
serializes operations

!
Core Data API is NOT Thread safe
!
Persistent Store Coordinator makes
it Thread Safe
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
Managed Object Context
Managed Object Context
Diego Freniche / @dfreniche / http://www.freniche.com
Persistent Object Store
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
NSXMLStoreType (XML only OS X, bad performance)!
NSSQLiteStoreType (partial object graph in memory)!
NSBinaryStoreType (kind of NIBs, poor performance)!
NSInMemoryStoreType (good for testing)
Makes the mapping between our App’s objects and the physical storage inside
the Persistent Object Store.
Supported Store Types
Diego Freniche / @dfreniche / http://www.freniche.com
Creating the Core Data Stack
!
-(void)setUpCoreDataStack	

{	

NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];	

NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];	

!
NSURL *url = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]
URLByAppendingPathComponent:@"Database.sqlite"];	

!
NSDictionary *options = @{NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,	

NSMigratePersistentStoresAutomaticallyOption:@YES};	

NSError *error = nil;	

NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error];	

if (!store)	

{	

NSLog(@"Error adding persistent store. Error %@",error);	

!
NSError *deleteError = nil;	

if ([[NSFileManager defaultManager] removeItemAtURL:url error:&deleteError])	

{	

error = nil;	

store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error];	

}	

!
if (!store)	

{	

// Also inform the user...	

NSLog(@"Failed to create persistent store. Error %@. Delete error %@",error,deleteError);	

abort();	

}	

}	

!
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];	

self.managedObjectContext.persistentStoreCoordinator = psc;	

}	

!
// http://commandshift.co.uk/blog/2013/09/07/the-core-data-stack/
Diego Freniche / http://www.freniche.com
DF Core Data Stack
Warning: really bad code ahead!
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Dependency injection? Or singletons FTW?
• It depends :-)
Diego Freniche / http://www.freniche.com
To create a Core Data Project
• Link against Core Data Framework

• Write some code to create a Core Data Stack

• Test it! In memory (better)
Diego Freniche / @dfreniche / http://www.freniche.com
SQL in SQLite
• http://sqlite.org/lang.html

• We can have a look at generated SQL: 

• -com.apple.CoreData.SQLDebug 1
• Schemes > Edit Scheme > Test > Arguments
Diego Freniche / @dfreniche / http://www.freniche.com
1
2
3
Diego Freniche / @dfreniche / http://www.freniche.com
Accessing SQLite
sqlitestudio.pl
Look for your databases in:
!
/Users/<usuario>/Library/Application
Support/iPhone Simulator/<versión>/
Applications/<ID App>/Documents/
<archivo SQLite>
Diego Freniche / @dfreniche / http://www.freniche.com
DDL: Data Definition Language
• CREATE DATABASE, CREATE TABLE, CREATE INDEX, ALTER TABLE, DROP
INDEX, ...

• All written by Core Data

• We DO NOT have to create anything: neither tables nor database

• If we make changes, Core Data alters tables, columns, indexes...
Diego Freniche / @dfreniche / http://www.freniche.com
Modelling
We need a Data Model file to “draw” our model
1st, create all our model’s entities, then add
attributes!
!
Can subclass NSManagedObject to use compiler-
time name checking, Xcode’s autofill,...
Diego Freniche / @dfreniche / http://www.freniche.com
Modelling
• New model versions: Editor > Add
Model Version

• Model (.xcdatamodeld) is a folder

• Last version has no number. Oldest
with higher number. WTF, Apple!
(WTF: What a Tricky Fact)

• 1st time we access model it
creates persintent store lazily
Select THIS
Diego Freniche / @dfreniche / http://www.freniche.com
Versioning and changes
• Activate always lightweight migration

• If we make changes to the model, not changing version, version used in the
model and version used to create DB doesn’t match: delete DB.

• Reseting Content and Settings.. in Simulator

• delete (by hand) .sqlite file
Diego Freniche / @dfreniche / http://www.freniche.com
NSManagedObject
NSManagedObject
NSManagedObjectContext
NSEntityDescription
Diego Freniche / @dfreniche / http://www.freniche.com
NSManagedObject
• base class implementing all “basic” object model behavior

• We can NOT use Core Data with NSObject, we HAVE TO use
NSManagedObject

• Our model classes inherit from NSManagedObject

• not mandatory, but...

• allows us to add logic, use @property, get notifications...

• have to be properly configured
Diego Freniche / @dfreniche / http://www.freniche.com
Entities Design
• Always add an order field
• Try to create a good UML diagram at first

• Yes, I’ve said UML!

• Have an NSString constant with every Entity’s name inside .h
Diego Freniche / @dfreniche / http://www.freniche.com
Extend NSManagedObject
• Editor > Create NSManagedObject subclass...

• creates @dynamic properties

• getter / setter generated in runtime (@property in compile time) 

• Core Data doesn’t know at compile time if the persistent store is going to
be XML or a DB (or in-memory)
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Entities Design Tips
• Always add field order
• Try to create a good UML diagram at first

• Have an NSString constant with every Entity’s name inside .h
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Extend NSManagedObject
• Editor > Create NSManagedObject subclass...

• creates @dynamic properties

• getter / setter generated in runtime (@property in compile time) 

• Core Data doesn’t know at compile time if the persistent store is going to
be XML or a DB (or in-memory)
Diego Freniche / @dfreniche / http://www.freniche.com
Extend NSManagedObject
• overwrite init to call designated initializer
!
-(id)init {
NSManagedObjectContext *context = [[CoreDataStack coreDataStack]
managedObjectContext];
return [self initWithEntity:[NSEntityDescription
entityForName:kRETROITEM_ENTITY inManagedObjectContext:context ]
insertIntoManagedObjectContext:context];
}
Diego Freniche / @dfreniche / http://www.freniche.com
Validate Properties
• One for every property, if we want it

• Passing parameter by reference

• It should return YES if validation is passed
!
-(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError;
Diego Freniche / @dfreniche / http://www.freniche.com
Validator for operations
• First thing: must call [super ...]

• Useful to check business rules (using several properties)
!
- (BOOL)validateForDelete:(NSError **)error
- (BOOL)validateForInsert:(NSError **)error
- (BOOL)validateForUpdate:(NSError **)error
Diego Freniche / @dfreniche / http://www.freniche.com
Support for KVO
• Good for Faults
!
- (void)willAccessValueForKey:(NSString *)key
Diego Freniche / @dfreniche / http://www.freniche.com
Inserting Entities (INSERT INTO)
!
// using NSEntityDescription. Pass: entity name and context
[NSEntityDescription insertNewObjectForEntityForName:@”RetroItems” inManagedObjectContext:context];
[retroItem setValue:@"Spectrum 48K" forKey:@"name"];
[retroItem setValue:@100.00 forKey:@"acquisitionCost"];
[retroItem setValue:[NSDate new] forKey:@"dateAcquired"];
insertNewObjectForEntityForName context save
Context
Diego Freniche / @dfreniche / http://www.freniche.com
Fetching entities (SELECT)
• Query with NSFetchRequest

• SELECT by definition is unordered

• At least we need to provide

• entity

• order by
Diego Freniche / @dfreniche / http://www.freniche.com
Step by Step fetch (Select)
!
NSManagedObjectContext *context = [[CoreDataStack coreDataStack] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:kRETRO_ITEM_ENTITY
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
[fetchRequest setSortDescriptors:@[sortDescriptor]];
NSError *error = nil;
NSArray *distincResults = [context executeFetchRequest:fetchRequest error:&error];
1
2
3
4
5
6
Diego Freniche / @dfreniche / http://www.freniche.com
Order querys
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fecha_max" ascending:YES];
NSManagedObject returned inside NSArray are unordered unless otherwise we
provide NSSortDescription.
!
1st, we create the sort descriptor
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
Then we add to our NSFetchRequest the sort descriptors array:
Diego Freniche / @dfreniche / http://www.freniche.com
Filtering querys
NSManagedObjectContext *moc = [self managedObjectContext];!
!
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Employee"
inManagedObjectContext:moc];!
!
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];!
[request setEntity:entityDescription];!
!
NSNumber *minimumSalary = ...;!
!
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(lastName LIKE[c] 'Worsley') AND (salary
> %@)", minimumSalary];!
!
[request setPredicate:predicate];!
!
NSError *error = nil;!
!
NSArray *array = [moc executeFetchRequest:request error:&error];!
NSFetchRequest returns an array of NSManagedObject. We can use a
NSPredicate to filter.
!
Filter/NSPredicate acts here as the SQL WHERE clause.
!
We need to add that query with setPredicate.
Diego Freniche / @dfreniche / http://www.freniche.com
• 	 CONTAINS: to query for strings that contain substrings.

• 	 ==: equality operator.

• 	 BEGINSWITH: a pre-made regular expression that looks for matches at the
beginning of a string.

• 	 MATCHES: regular expression-like search.

• 	 ENDSWITH: opposite of BEGINSWITH.

• 	 <, >: less than and greater than.
Diego Freniche / @dfreniche / http://www.freniche.com
Delete Entities (DELETE)
+ (void)deleteInstancesForEntityName:(NSString *)entityName inContext:(NSManagedObjectContext *)context {
!
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
!
[fetch setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:context]];
NSError *error = nil;
NSArray *dataObjects = [context executeFetchRequest:fetch error:&error];
for (NSManagedObject *dataObject in dataObjects) {
[context deleteObject:dataObject];
}
!
NSError *saveError = nil;
[context save:&saveError];
}
Diego Freniche / @dfreniche / http://www.freniche.com
Object identificator
!
NSManagedObjectID *moID = [managedObject objectID];
!
-(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID
error:(NSError **)error
Diego Freniche / @dfreniche / http://www.freniche.com
Accessing Properties
Sometimes we don’t want the whole object (NSManagedObject) only the value of a property applying a function
(max, min, etc.).
NSFetchRequest *request = [[NSFetchRequest alloc] init];!
!
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];!
!
[request setEntity:entity];
1. Create NSFetchRequest as usual
[request setResultType:NSDictionaryResultType];
2. Tell NSFetchRequest to return NSDictionary instead NSArray:
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"creationDate"];!
!
NSExpression *minExpression = [NSExpression expressionForFunction:@"min:" arguments:[NSArray
arrayWithObject:keyPathExpression]];
3. Define the field to calc upon (NSExpression), then the function
Diego Freniche / @dfreniche / http://www.freniche.com
Accessing Properties
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];!
!
[expressionDescription setName:@"minDate"];!
!
[expressionDescription setExpression:minExpression];!
!
[expressionDescription setExpressionResultType:NSDateAttributeType];
4. Create a NSExpressionDescription:
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];!
!
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
5. Set in the query the properties to fetch
if ([objects count] > 0) {!
NSLog(@"Minimum date: %@", [[objects objectAtIndex:0] valueForKey:@"minDate"]);!
}
6. Access our result:
Diego Freniche / @dfreniche / http://www.freniche.com
Using Blocks to Sort
If Sorting is not trivial maybe NSSortDescription is not enough.
[[NSSortDescriptor alloc] initWithKey:<#(NSString *)#>
ascending:<#(BOOL)#>
comparator:<#^NSComparisonResult(id obj1, id obj2)cmptr#>
^(id a, id b) {
NSNumber *lat1 = [[a valueForKey:@"latitude"] doubleValue];
NSNumber *lon1 = [a valueForKey:@"longitude"] doubleValue];
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:lat1 longitude:lon1];
NSNumber *lat2 = [[b valueForKey:@"latitude"] doubleValue];
NSNumber *lon2 = [b valueForKey:@"longitude"] doubleValue];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:lat2 longitude:lon2];
CLLocationDistance dist_a= [loc1 distanceFromLocation:locUser];
CLLocationDistance dist_b= [loc2 distanceFromLocation:locUser];
if ( dist_a < dist_b ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( dist_a > dist_b) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}];
Ejemplo de ordenación de distancias:
Diego Freniche / @dfreniche / http://www.freniche.com
Relationship example
NSManagedObjectContext *context = [self managedObjectContext];!
!
NSManagedObject *failedBankInfo = [NSEntityDescription!
insertNewObjectForEntityForName:@"FailedBankInfo"!
inManagedObjectContext:context];!
!
[failedBankInfo setValue:@"Test Bank" forKey:@"name"];!
[failedBankInfo setValue:@"Testville" forKey:@"city"];!
[failedBankInfo setValue:@"Testland" forKey:@"state"];!
!
NSManagedObject *failedBankDetails = [NSEntityDescription!
insertNewObjectForEntityForName:@"FailedBankDetails"!
inManagedObjectContext:context];!
!
[failedBankDetails setValue:[NSDate date] forKey:@"closeDate"];!
[failedBankDetails setValue:[NSDate date] forKey:@"updateDate"];!
[failedBankDetails setValue:[NSNumber numberWithInt:12345] forKey:@"zip"];!
[failedBankDetails setValue:failedBankInfo forKey:@"info"];!
!
[failedBankInfo setValue:failedBankDetails forKey:@"details"];!
!
NSError *error;!
!
if (![context save:&amp;error]) {!
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);!
}!
Writing
Diego Freniche / @dfreniche / http://www.freniche.com
Relationship example
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];!
!
NSEntityDescription *entity = [NSEntityDescription!
entityForName:@"FailedBankInfo" inManagedObjectContext:context];!
!
[fetchRequest setEntity:entity];!
!
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];!
!
for (NSManagedObject *info in fetchedObjects) {!
!
NSLog(@"Name: %@", [info valueForKey:@"name"]);!
!
NSManagedObject *details = [info valueForKey:@"details"];!
NSLog(@"Zip: %@", [details valueForKey:@"zip"]);!
}!
Reading
Diego Freniche / @dfreniche / http://www.freniche.com
NSFetchedResultsController
• Controller without interface

• Purpose: “feed” with data an UITableView

• Protocol NSFetchedResultsControllerDelegate

• section “Typical Use”: there’s the code found in template

• connected to a Context: if there are changes of any object inside that
context it receives a notification and updates automatically
Diego Freniche / @dfreniche / http://www.freniche.com
NSFetchedResultsController
Context
NSManagedObject
NSManagedObject
NSManagedObject
SQLite
UITableView NSFetchedResultsController
???
delegate
Diego Freniche / @dfreniche / http://www.freniche.com
All needed code for NSFetchedResults Cont.
• In the Apple Docs!
Diego Freniche / http://www.freniche.com
Idea: use Mogenerator
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Mogenerator
created by Jonathan 'Wolf' Rentzsch
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Mogenerator (quoting from the web page)
• http://rentzsch.github.io/mogenerator/

• generates Objective-C code for your Core Data custom classes

• Unlike Xcode, mogenerator manages two classes per entity: one for
machines, one for humans

• The machine class can always be overwritten to match the data model,
with humans’ work effortlessly preserved
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Installing mogenerator
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Two classes
• _MyClass.*: machine generated

• *MyClass.*: human edited

!
• Never, ever recreate the classes
again from the Core Data Model
Diego Freniche / http://www.freniche.com
#import "_RetroItem.h"
!
@interface RetroItem : _RetroItem {}
// Custom logic goes here.
@end
#import "RetroItem.h"
!
!
@interface RetroItem ()
!
// Private interface goes here.
!
@end
!
!
@implementation RetroItem
!
// Custom logic goes here.
!
@end
Two classes
Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com
Using it
• it’s a script, so we can launch it from command line

• using iTerm, DTerm, etc.

• Best way: to have it inside our project

• Create a new Aggregate Target (New Target > Other > Aggregate)

• Add Build Phase > Add Run Script
!
mogenerator --template-var arc=true -m RetroStuffTracker/
RetroStuffTracker.xcdatamodeld/RetroStuffTracker.xcdatamodel/
Diego Freniche / http://www.freniche.com
Diego Freniche / http://www.freniche.com
Idea: use Magical Record
Diego Freniche / http://www.freniche.com
Magical Record Demo
Warning: really bad code ahead!
Diego Freniche / http://www.freniche.com
Magical record != avoid Core Data at all costs
• Just a bunch of categories to help you write less code

• You have to know your sh*t

• CocoaPods friendly

• Ideal: use Unit testing + Mogenerator + CocoaPods + Magical Record

• My point: 7 people, 7 ideas, all great

• all different
Diego Freniche / http://www.freniche.com
Idea: using asserts to check threads
Diego Freniche / http://www.freniche.com
Asserts
• Check if we are running UI code in the UI Thread

• Check if we are NOT running Core Data code in the UI Thread
!
#ifndef	
  CDHelloWord_DFThreadAsserts_h	
  
#define	
  CDHelloWord_DFThreadAsserts_h	
  
!
#define	
  DF_ASSERT_MAIN_THREAD	
  [NSThread	
  isMainThread]?:(NSLog(@"NOT	
  IN	
  MAIN	
  THREAD"),abort())	
  
#define	
  DF_ASSERT_NOT_MAIN_THREAD	
  ![NSThread	
  isMainThread]?:(NSLog(@"IN	
  MAIN	
  THREAD,	
  BUT	
  NOT	
  EXPECTED"),abort())	
  
!
!
#endif	
  
Diego Freniche / http://www.freniche.com
Idea: create a common UITableView/Core data
class
Questions?
Diego Freniche / @dfreniche / http://www.freniche.com
Attributions
• http://www.flickr.com/photos/paldies/85684217/

• http://www.flickr.com/photos/56380734@N05/6808753611/

• http://www.flickr.com/photos/msimdottv/4339697089/

• http://www.flickr.com/photos/mobilestreetlife/4179063482/

• http://www.flickr.com/photos/owldreams/4428782193/

• http://www.flickr.com/photos/miss_pupik/73160522/

• http://kfannerd713.deviantart.com/art/UNICORN-PUKING-RAINBOWS-WHAAAA-152117816

• http://www.flickr.com/photos/wwworks/4759535950/

• http://www.flickr.com/photos/barto/28135419/sizes/l/in/photolist-3ucFr-7aiwZ-aqWUu-bLebi-cDeVC-jt2YW-jWW1t-kQ25f-m86XP-swafK-yHMbE-yHMcc-yHMda-

Mais conteúdo relacionado

Mais procurados

Intro to Theming Drupal, FOSSLC Summer Camp 2010
Intro to Theming Drupal, FOSSLC Summer Camp 2010Intro to Theming Drupal, FOSSLC Summer Camp 2010
Intro to Theming Drupal, FOSSLC Summer Camp 2010
Emma Jane Hogbin Westby
 
Best Practices for Front-End Django Developers
Best Practices for Front-End Django DevelopersBest Practices for Front-End Django Developers
Best Practices for Front-End Django Developers
Christine Cheung
 
Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13
Stephan Hochdörfer
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)
Jacob Kaplan-Moss
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
Fabien Potencier
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
Advanced JavaScript Development
Advanced JavaScript DevelopmentAdvanced JavaScript Development
Advanced JavaScript Development
Jussi Pohjolainen
 

Mais procurados (20)

The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
Hybrid Web Applications
Hybrid Web ApplicationsHybrid Web Applications
Hybrid Web Applications
 
Intro to Theming Drupal, FOSSLC Summer Camp 2010
Intro to Theming Drupal, FOSSLC Summer Camp 2010Intro to Theming Drupal, FOSSLC Summer Camp 2010
Intro to Theming Drupal, FOSSLC Summer Camp 2010
 
Best Practices for Front-End Django Developers
Best Practices for Front-End Django DevelopersBest Practices for Front-End Django Developers
Best Practices for Front-End Django Developers
 
Create responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJSCreate responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJS
 
Django Architecture Introduction
Django Architecture IntroductionDjango Architecture Introduction
Django Architecture Introduction
 
Ant User Guide
Ant User GuideAnt User Guide
Ant User Guide
 
Becoming A Drupal Master Builder
Becoming A Drupal Master BuilderBecoming A Drupal Master Builder
Becoming A Drupal Master Builder
 
Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tour
 
Working with the django admin
Working with the django admin Working with the django admin
Working with the django admin
 
Web Site Tune-Up - Improve Your Googlejuice
Web Site Tune-Up - Improve Your GooglejuiceWeb Site Tune-Up - Improve Your Googlejuice
Web Site Tune-Up - Improve Your Googlejuice
 
Drupal Flyover, CMS Expo
Drupal Flyover, CMS ExpoDrupal Flyover, CMS Expo
Drupal Flyover, CMS Expo
 
Design to Theme @ CMSExpo
Design to Theme @ CMSExpoDesign to Theme @ CMSExpo
Design to Theme @ CMSExpo
 
Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13
 
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
Phase2 OpenPublish Presentation SF SemWeb Meetup, April 28, 2009
 
Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Echo HTML5
Echo HTML5Echo HTML5
Echo HTML5
 
Advanced JavaScript Development
Advanced JavaScript DevelopmentAdvanced JavaScript Development
Advanced JavaScript Development
 

Destaque (8)

Magister of Entrepreneurship - Social Development
Magister of Entrepreneurship - Social DevelopmentMagister of Entrepreneurship - Social Development
Magister of Entrepreneurship - Social Development
 
208140015 윤신애
208140015 윤신애208140015 윤신애
208140015 윤신애
 
Microsite
MicrositeMicrosite
Microsite
 
A New Haiti
A New HaitiA New Haiti
A New Haiti
 
Core data basic Workshop slides NSSpain 2013
Core data basic Workshop slides NSSpain 2013Core data basic Workshop slides NSSpain 2013
Core data basic Workshop slides NSSpain 2013
 
Core data intermediate Workshop at NSSpain 2013
Core data intermediate Workshop at NSSpain 2013Core data intermediate Workshop at NSSpain 2013
Core data intermediate Workshop at NSSpain 2013
 
Disaster Relief Village
Disaster Relief VillageDisaster Relief Village
Disaster Relief Village
 
Limpiando espero la arquitectura que yo quiero
Limpiando espero la arquitectura que yo quieroLimpiando espero la arquitectura que yo quiero
Limpiando espero la arquitectura que yo quiero
 

Semelhante a Core data WIPJam workshop @ MWC'14

Data Abstraction for Large Web Applications
Data Abstraction for Large Web ApplicationsData Abstraction for Large Web Applications
Data Abstraction for Large Web Applications
brandonsavage
 
SharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure FunctionsSharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure Functions
Sébastien Levert
 
Buildingsocialanalyticstoolwithmongodb
BuildingsocialanalyticstoolwithmongodbBuildingsocialanalyticstoolwithmongodb
Buildingsocialanalyticstoolwithmongodb
MongoDB APAC
 
Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12
Stephan Hochdörfer
 

Semelhante a Core data WIPJam workshop @ MWC'14 (20)

CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!CoreData - there is an ORM you can like!
CoreData - there is an ORM you can like!
 
Data Abstraction for Large Web Applications
Data Abstraction for Large Web ApplicationsData Abstraction for Large Web Applications
Data Abstraction for Large Web Applications
 
Drupal performance and scalability
Drupal performance and scalabilityDrupal performance and scalability
Drupal performance and scalability
 
Core data orlando i os dev group
Core data   orlando i os dev groupCore data   orlando i os dev group
Core data orlando i os dev group
 
React nativebeginner1
React nativebeginner1React nativebeginner1
React nativebeginner1
 
Make your Backbone Application dance
Make your Backbone Application danceMake your Backbone Application dance
Make your Backbone Application dance
 
Drupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to PluginDrupal 8, Where Did the Code Go? From Info Hook to Plugin
Drupal 8, Where Did the Code Go? From Info Hook to Plugin
 
SharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure FunctionsSharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure Functions
 
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
 
JS Essence
JS EssenceJS Essence
JS Essence
 
Intro to appcelerator
Intro to appceleratorIntro to appcelerator
Intro to appcelerator
 
BackboneJS Training - Giving Backbone to your applications
BackboneJS Training - Giving Backbone to your applicationsBackboneJS Training - Giving Backbone to your applications
BackboneJS Training - Giving Backbone to your applications
 
Buildingsocialanalyticstoolwithmongodb
BuildingsocialanalyticstoolwithmongodbBuildingsocialanalyticstoolwithmongodb
Buildingsocialanalyticstoolwithmongodb
 
Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12
 
Find your data - using GraphDB capabilities in XPages applications - ICS.UG 2016
Find your data - using GraphDB capabilities in XPages applications - ICS.UG 2016Find your data - using GraphDB capabilities in XPages applications - ICS.UG 2016
Find your data - using GraphDB capabilities in XPages applications - ICS.UG 2016
 
Iphone programming: Core Data Tutorial for iOS
Iphone programming: Core Data Tutorial for iOSIphone programming: Core Data Tutorial for iOS
Iphone programming: Core Data Tutorial for iOS
 
Analyse Yourself
Analyse YourselfAnalyse Yourself
Analyse Yourself
 
Data Migrations in the App Engine Datastore
Data Migrations in the App Engine DatastoreData Migrations in the App Engine Datastore
Data Migrations in the App Engine Datastore
 
Mobile native-hacks
Mobile native-hacksMobile native-hacks
Mobile native-hacks
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 

Mais de Diego Freniche Brito

Mais de Diego Freniche Brito (7)

Los mejores consejos para migrar de RDBMS a MongoDB.pptx.pdf
Los mejores consejos para migrar de RDBMS a MongoDB.pptx.pdfLos mejores consejos para migrar de RDBMS a MongoDB.pptx.pdf
Los mejores consejos para migrar de RDBMS a MongoDB.pptx.pdf
 
From Mobile to MongoDB: Store your app's data using Realm
From Mobile to MongoDB: Store your app's data using RealmFrom Mobile to MongoDB: Store your app's data using Realm
From Mobile to MongoDB: Store your app's data using Realm
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
 
Functional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented ProgrammersFunctional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented Programmers
 
Cocoa pods iOSDevUK 14 talk: managing your libraries
Cocoa pods iOSDevUK 14 talk: managing your librariesCocoa pods iOSDevUK 14 talk: managing your libraries
Cocoa pods iOSDevUK 14 talk: managing your libraries
 
Swift as a scripting language iOSDevUK14 Lightning talk
Swift as a scripting language iOSDevUK14 Lightning talkSwift as a scripting language iOSDevUK14 Lightning talk
Swift as a scripting language iOSDevUK14 Lightning talk
 
Charla XVII Beta Beers Sevilla: ¿Ágil? Como la rodilla de un click
Charla XVII Beta Beers Sevilla: ¿Ágil? Como la rodilla de un clickCharla XVII Beta Beers Sevilla: ¿Ágil? Como la rodilla de un click
Charla XVII Beta Beers Sevilla: ¿Ágil? Como la rodilla de un click
 

Último

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Último (20)

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 

Core data WIPJam workshop @ MWC'14

  • 1. Diego Freniche / http://www.freniche.com Core Data in 547 easy steps slide 1/373
  • 2. Diego Freniche / @dfreniche / http://www.freniche.com Core Data Workshop
  • 3. Diego Freniche: programmer & teacher • @dfreniche • Freelance Mobile developer: iOS/Android/BB10/ webOS/... • In a former life Java Certifications Collector: SCJP 1.5, SCJP 1.6, SCWCD 1.5, SCBCD 1.3 • Some languages: BASIC, PASCAL, C, C++, Delphi, COBOL, Clipper, Visual Basic, Java, JavaScript, Objective-C Hello, World!
  • 4. Diego Freniche / http://www.freniche.com Core Data: developer’s first impression
  • 5. Diego Freniche / http://www.freniche.com
  • 6. Diego Freniche / @dfreniche / http://www.freniche.com Core Data Hello World!
  • 7. Diego Freniche / @dfreniche / http://www.freniche.com That’s easy peasy
  • 8. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Apple’s code ! - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } !#pragma mark - Core Data stack !// Returns the managed object context for the application. // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. - (NSManagedObjectContext *)managedObjectContext { if (_managedObjectContext != nil) { return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _managedObjectContext = [[NSManagedObjectContext alloc] init]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return _managedObjectContext; } !// Returns the managed object model for the application. // If the model doesn't already exist, it is created from the application's model. - (NSManagedObjectModel *)managedObjectModel { if (_managedObjectModel != nil) { return _managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Test" withExtension:@"momd"]; _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return _managedObjectModel; } !// Returns the persistent store coordinator for the application. // If the coordinator doesn't already exist, it is created and the application's store added to it. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (_persistentStoreCoordinator != nil) { return _persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Test.sqlite"]; NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { /* Replace this implementation with code to handle the error appropriately. abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. Typical reasons for an error here include: * The persistent store is not accessible; * The schema for the persistent store is incompatible with current managed object model. Check the error message to determine what the actual problem was. If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. If you encounter schema incompatibility errors during development, you can reduce their frequency by: * Simply deleting the existing store: [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] * Performing automatic lightweight migration by passing the following dictionary as the options parameter: @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _persistentStoreCoordinator; } !#pragma mark - Application's Documents directory !// Returns the URL to the application's Documents directory. - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; }
  • 9. Diego Freniche / @dfreniche / http://www.freniche.com Corollary • Never, ever use the Core Data checkbox • BIG design flaws: • Core Data Stack coupled to AppDelegate: • can’t reuse in other projects • separations of concerns, anyone? • ugly! and just ONE Core Data Stack • They don’t even use a custom class
  • 10. Diego Freniche / @dfreniche / http://www.freniche.com What is Core Data? • Poll • A Framework. Must be important: its name starts with “Core” • An ORM • The model of your App • Technology to help you that has a steep learning curve
  • 11. Diego Freniche / @dfreniche / http://www.freniche.com One of the problems • Objet - Relational impedance • SQL: 70s/80s • OOP: 80s-
  • 12. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition id name idCard Person +name: String +idCard: idCard +bankAccout: bankAccount idCard +number: int +letter: char +checkLetter() VARCHAR ¿?
  • 13. Diego Freniche / @dfreniche / http://www.freniche.com Employee +empNumber: int Person +name: String +idCard: idCard Exhibit 2: inheritance Hyena Politician +moneyTaken: double
  • 14. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 3: collection modelling Person +name: String +bills: Bill[] Bill 0..*1 http://en.wikipedia.org/wiki/First_normal_form
  • 15. Diego Freniche / @dfreniche / http://www.freniche.com Relational World • tables • cartesian products • rows/ columns • normal forms • Objects • object collections • composition • inheritance OO World
  • 16. Diego Freniche / @dfreniche / http://www.freniche.com The solution: ORM • Object Relational Mapper • Hibernate (Java, .Net) • Core Data (Cocoa) • Core Data is our model • can persist our objects in several ways
  • 17. Diego Freniche / @dfreniche / http://www.freniche.com Which problems will Core Data help me solve? • Persist my data • Cache online data • to speed up things • to show something to the user when (if) there’s no Internet connection • Navigate the object graph: • [([Company allEmployees][0]).boss name]; • Maintain ViewControllers in sync
  • 18. Diego Freniche / @dfreniche / http://www.freniche.com Don’t fight the Frameworks! • Yes! You need to learn them! • Everything well thought-out to work with Core Data • Working with databases without Core Data? • not so much fun! • reinvent the wheel • this is not JavaScript-Land!
  • 19. Diego Freniche / @dfreniche / http://www.freniche.com Core Data terms • Entity • an entity in our model == Object in memory == row in table • Attribute • Relationship • Object graph http://ogre.berniecode.com/ogre_white_paper
  • 20. Diego Freniche / @dfreniche / http://www.freniche.com To get the most out of Core Data • You need to understand: • KVC, KVO • ARC, memory management • delegate & MVC patterns • that singletons are evil (more or less)
  • 21. Diego Freniche / @dfreniche / http://www.freniche.com The Core Data Stack Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  • 22. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Context Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  • 23. Diego Freniche / @dfreniche / http://www.freniche.com Our Model NSManagedObject NSManagedObject NSManagedObject NSManagedObject Persisted NSManagedObjectContext NSObject In memory only
  • 24. Diego Freniche / @dfreniche / http://www.freniche.com Move away from NSObject! ! @interface  MyClass  :  NSObject   ! @end     ! @interface  MyClass  :  NSManagedObject   ! @end  
  • 25. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Context: MOC • Managed Object Context: in-memory space where CD manages all our model’s objects. • All CRUD is done against a MOC. We persist data using [context save:] • Our model’s objects are Managed Objects. • The MOC needs a Persistent Store Coordinator to save the object graph in persistent store.
  • 26. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  • 27. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model • Maps our model objects into database tables. • Objects == NSManagedObject • Classes == NSEntityDescription • We describe our App entities inside a MOM • stored inside .xcdatamodeld files in Xcode. Compiles into .momd • graphic editor / class generator (dumb)
  • 28. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  • 29. Diego Freniche / @dfreniche / http://www.freniche.com Persistent Store Coordinador Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model Makes the mapping between our App’s objects and the physical storage inside the Persistent Object Store. 99% time we’ll work with ONE Object Store, but it’s possible use more than one. For example, a sqlite DB with recipes and another DB with notes, stars, etc. Coordinator: single façade to work with different Stores. ! A managed object context can then create an object graph based on the union of all the data stores the coordinator covers Persistent Object Store
  • 30. Diego Freniche / http://www.freniche.com Persistent Store Coordinador Called Coordinator for a reason: serializes operations ! Core Data API is NOT Thread safe ! Persistent Store Coordinator makes it Thread Safe Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model Managed Object Context Managed Object Context
  • 31. Diego Freniche / @dfreniche / http://www.freniche.com Persistent Object Store Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model NSXMLStoreType (XML only OS X, bad performance)! NSSQLiteStoreType (partial object graph in memory)! NSBinaryStoreType (kind of NIBs, poor performance)! NSInMemoryStoreType (good for testing) Makes the mapping between our App’s objects and the physical storage inside the Persistent Object Store. Supported Store Types
  • 32. Diego Freniche / @dfreniche / http://www.freniche.com Creating the Core Data Stack ! -(void)setUpCoreDataStack { NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]; NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; ! NSURL *url = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"Database.sqlite"]; ! NSDictionary *options = @{NSPersistentStoreFileProtectionKey: NSFileProtectionComplete, NSMigratePersistentStoresAutomaticallyOption:@YES}; NSError *error = nil; NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error]; if (!store) { NSLog(@"Error adding persistent store. Error %@",error); ! NSError *deleteError = nil; if ([[NSFileManager defaultManager] removeItemAtURL:url error:&deleteError]) { error = nil; store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error]; } ! if (!store) { // Also inform the user... NSLog(@"Failed to create persistent store. Error %@. Delete error %@",error,deleteError); abort(); } } ! self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; self.managedObjectContext.persistentStoreCoordinator = psc; } ! // http://commandshift.co.uk/blog/2013/09/07/the-core-data-stack/
  • 33. Diego Freniche / http://www.freniche.com DF Core Data Stack Warning: really bad code ahead!
  • 34. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Dependency injection? Or singletons FTW? • It depends :-)
  • 35. Diego Freniche / http://www.freniche.com To create a Core Data Project • Link against Core Data Framework • Write some code to create a Core Data Stack • Test it! In memory (better)
  • 36. Diego Freniche / @dfreniche / http://www.freniche.com SQL in SQLite • http://sqlite.org/lang.html • We can have a look at generated SQL: • -com.apple.CoreData.SQLDebug 1 • Schemes > Edit Scheme > Test > Arguments
  • 37. Diego Freniche / @dfreniche / http://www.freniche.com 1 2 3
  • 38. Diego Freniche / @dfreniche / http://www.freniche.com Accessing SQLite sqlitestudio.pl Look for your databases in: ! /Users/<usuario>/Library/Application Support/iPhone Simulator/<versión>/ Applications/<ID App>/Documents/ <archivo SQLite>
  • 39. Diego Freniche / @dfreniche / http://www.freniche.com DDL: Data Definition Language • CREATE DATABASE, CREATE TABLE, CREATE INDEX, ALTER TABLE, DROP INDEX, ... • All written by Core Data • We DO NOT have to create anything: neither tables nor database • If we make changes, Core Data alters tables, columns, indexes...
  • 40. Diego Freniche / @dfreniche / http://www.freniche.com Modelling We need a Data Model file to “draw” our model 1st, create all our model’s entities, then add attributes! ! Can subclass NSManagedObject to use compiler- time name checking, Xcode’s autofill,...
  • 41. Diego Freniche / @dfreniche / http://www.freniche.com Modelling • New model versions: Editor > Add Model Version • Model (.xcdatamodeld) is a folder • Last version has no number. Oldest with higher number. WTF, Apple! (WTF: What a Tricky Fact) • 1st time we access model it creates persintent store lazily Select THIS
  • 42. Diego Freniche / @dfreniche / http://www.freniche.com Versioning and changes • Activate always lightweight migration • If we make changes to the model, not changing version, version used in the model and version used to create DB doesn’t match: delete DB. • Reseting Content and Settings.. in Simulator • delete (by hand) .sqlite file
  • 43. Diego Freniche / @dfreniche / http://www.freniche.com NSManagedObject NSManagedObject NSManagedObjectContext NSEntityDescription
  • 44. Diego Freniche / @dfreniche / http://www.freniche.com NSManagedObject • base class implementing all “basic” object model behavior • We can NOT use Core Data with NSObject, we HAVE TO use NSManagedObject • Our model classes inherit from NSManagedObject • not mandatory, but... • allows us to add logic, use @property, get notifications... • have to be properly configured
  • 45. Diego Freniche / @dfreniche / http://www.freniche.com Entities Design • Always add an order field • Try to create a good UML diagram at first • Yes, I’ve said UML! • Have an NSString constant with every Entity’s name inside .h
  • 46. Diego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • Editor > Create NSManagedObject subclass... • creates @dynamic properties • getter / setter generated in runtime (@property in compile time) • Core Data doesn’t know at compile time if the persistent store is going to be XML or a DB (or in-memory)
  • 47. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Entities Design Tips • Always add field order • Try to create a good UML diagram at first • Have an NSString constant with every Entity’s name inside .h
  • 48. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • Editor > Create NSManagedObject subclass... • creates @dynamic properties • getter / setter generated in runtime (@property in compile time) • Core Data doesn’t know at compile time if the persistent store is going to be XML or a DB (or in-memory)
  • 49. Diego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • overwrite init to call designated initializer ! -(id)init { NSManagedObjectContext *context = [[CoreDataStack coreDataStack] managedObjectContext]; return [self initWithEntity:[NSEntityDescription entityForName:kRETROITEM_ENTITY inManagedObjectContext:context ] insertIntoManagedObjectContext:context]; }
  • 50. Diego Freniche / @dfreniche / http://www.freniche.com Validate Properties • One for every property, if we want it • Passing parameter by reference • It should return YES if validation is passed ! -(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError;
  • 51. Diego Freniche / @dfreniche / http://www.freniche.com Validator for operations • First thing: must call [super ...] • Useful to check business rules (using several properties) ! - (BOOL)validateForDelete:(NSError **)error - (BOOL)validateForInsert:(NSError **)error - (BOOL)validateForUpdate:(NSError **)error
  • 52. Diego Freniche / @dfreniche / http://www.freniche.com Support for KVO • Good for Faults ! - (void)willAccessValueForKey:(NSString *)key
  • 53. Diego Freniche / @dfreniche / http://www.freniche.com Inserting Entities (INSERT INTO) ! // using NSEntityDescription. Pass: entity name and context [NSEntityDescription insertNewObjectForEntityForName:@”RetroItems” inManagedObjectContext:context]; [retroItem setValue:@"Spectrum 48K" forKey:@"name"]; [retroItem setValue:@100.00 forKey:@"acquisitionCost"]; [retroItem setValue:[NSDate new] forKey:@"dateAcquired"]; insertNewObjectForEntityForName context save Context
  • 54. Diego Freniche / @dfreniche / http://www.freniche.com Fetching entities (SELECT) • Query with NSFetchRequest • SELECT by definition is unordered • At least we need to provide • entity • order by
  • 55. Diego Freniche / @dfreniche / http://www.freniche.com Step by Step fetch (Select) ! NSManagedObjectContext *context = [[CoreDataStack coreDataStack] managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:kRETRO_ITEM_ENTITY inManagedObjectContext:context]; [fetchRequest setEntity:entity]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; NSError *error = nil; NSArray *distincResults = [context executeFetchRequest:fetchRequest error:&error]; 1 2 3 4 5 6
  • 56. Diego Freniche / @dfreniche / http://www.freniche.com Order querys NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fecha_max" ascending:YES]; NSManagedObject returned inside NSArray are unordered unless otherwise we provide NSSortDescription. ! 1st, we create the sort descriptor [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; Then we add to our NSFetchRequest the sort descriptors array:
  • 57. Diego Freniche / @dfreniche / http://www.freniche.com Filtering querys NSManagedObjectContext *moc = [self managedObjectContext];! ! NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:moc];! ! NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];! [request setEntity:entityDescription];! ! NSNumber *minimumSalary = ...;! ! NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary];! ! [request setPredicate:predicate];! ! NSError *error = nil;! ! NSArray *array = [moc executeFetchRequest:request error:&error];! NSFetchRequest returns an array of NSManagedObject. We can use a NSPredicate to filter. ! Filter/NSPredicate acts here as the SQL WHERE clause. ! We need to add that query with setPredicate.
  • 58. Diego Freniche / @dfreniche / http://www.freniche.com • CONTAINS: to query for strings that contain substrings. • ==: equality operator. • BEGINSWITH: a pre-made regular expression that looks for matches at the beginning of a string. • MATCHES: regular expression-like search. • ENDSWITH: opposite of BEGINSWITH. • <, >: less than and greater than.
  • 59. Diego Freniche / @dfreniche / http://www.freniche.com Delete Entities (DELETE) + (void)deleteInstancesForEntityName:(NSString *)entityName inContext:(NSManagedObjectContext *)context { ! NSFetchRequest *fetch = [[NSFetchRequest alloc] init]; ! [fetch setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:context]]; NSError *error = nil; NSArray *dataObjects = [context executeFetchRequest:fetch error:&error]; for (NSManagedObject *dataObject in dataObjects) { [context deleteObject:dataObject]; } ! NSError *saveError = nil; [context save:&saveError]; }
  • 60. Diego Freniche / @dfreniche / http://www.freniche.com Object identificator ! NSManagedObjectID *moID = [managedObject objectID]; ! -(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID error:(NSError **)error
  • 61. Diego Freniche / @dfreniche / http://www.freniche.com Accessing Properties Sometimes we don’t want the whole object (NSManagedObject) only the value of a property applying a function (max, min, etc.). NSFetchRequest *request = [[NSFetchRequest alloc] init];! ! NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];! ! [request setEntity:entity]; 1. Create NSFetchRequest as usual [request setResultType:NSDictionaryResultType]; 2. Tell NSFetchRequest to return NSDictionary instead NSArray: NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"creationDate"];! ! NSExpression *minExpression = [NSExpression expressionForFunction:@"min:" arguments:[NSArray arrayWithObject:keyPathExpression]]; 3. Define the field to calc upon (NSExpression), then the function
  • 62. Diego Freniche / @dfreniche / http://www.freniche.com Accessing Properties NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];! ! [expressionDescription setName:@"minDate"];! ! [expressionDescription setExpression:minExpression];! ! [expressionDescription setExpressionResultType:NSDateAttributeType]; 4. Create a NSExpressionDescription: [request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];! ! NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error]; 5. Set in the query the properties to fetch if ([objects count] > 0) {! NSLog(@"Minimum date: %@", [[objects objectAtIndex:0] valueForKey:@"minDate"]);! } 6. Access our result:
  • 63. Diego Freniche / @dfreniche / http://www.freniche.com Using Blocks to Sort If Sorting is not trivial maybe NSSortDescription is not enough. [[NSSortDescriptor alloc] initWithKey:<#(NSString *)#> ascending:<#(BOOL)#> comparator:<#^NSComparisonResult(id obj1, id obj2)cmptr#> ^(id a, id b) { NSNumber *lat1 = [[a valueForKey:@"latitude"] doubleValue]; NSNumber *lon1 = [a valueForKey:@"longitude"] doubleValue]; CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:lat1 longitude:lon1]; NSNumber *lat2 = [[b valueForKey:@"latitude"] doubleValue]; NSNumber *lon2 = [b valueForKey:@"longitude"] doubleValue]; CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:lat2 longitude:lon2]; CLLocationDistance dist_a= [loc1 distanceFromLocation:locUser]; CLLocationDistance dist_b= [loc2 distanceFromLocation:locUser]; if ( dist_a < dist_b ) { return (NSComparisonResult)NSOrderedAscending; } else if ( dist_a > dist_b) { return (NSComparisonResult)NSOrderedDescending; } else { return (NSComparisonResult)NSOrderedSame; } }]; Ejemplo de ordenación de distancias:
  • 64. Diego Freniche / @dfreniche / http://www.freniche.com Relationship example NSManagedObjectContext *context = [self managedObjectContext];! ! NSManagedObject *failedBankInfo = [NSEntityDescription! insertNewObjectForEntityForName:@"FailedBankInfo"! inManagedObjectContext:context];! ! [failedBankInfo setValue:@"Test Bank" forKey:@"name"];! [failedBankInfo setValue:@"Testville" forKey:@"city"];! [failedBankInfo setValue:@"Testland" forKey:@"state"];! ! NSManagedObject *failedBankDetails = [NSEntityDescription! insertNewObjectForEntityForName:@"FailedBankDetails"! inManagedObjectContext:context];! ! [failedBankDetails setValue:[NSDate date] forKey:@"closeDate"];! [failedBankDetails setValue:[NSDate date] forKey:@"updateDate"];! [failedBankDetails setValue:[NSNumber numberWithInt:12345] forKey:@"zip"];! [failedBankDetails setValue:failedBankInfo forKey:@"info"];! ! [failedBankInfo setValue:failedBankDetails forKey:@"details"];! ! NSError *error;! ! if (![context save:&amp;error]) {! NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);! }! Writing
  • 65. Diego Freniche / @dfreniche / http://www.freniche.com Relationship example NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];! ! NSEntityDescription *entity = [NSEntityDescription! entityForName:@"FailedBankInfo" inManagedObjectContext:context];! ! [fetchRequest setEntity:entity];! ! NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];! ! for (NSManagedObject *info in fetchedObjects) {! ! NSLog(@"Name: %@", [info valueForKey:@"name"]);! ! NSManagedObject *details = [info valueForKey:@"details"];! NSLog(@"Zip: %@", [details valueForKey:@"zip"]);! }! Reading
  • 66. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController • Controller without interface • Purpose: “feed” with data an UITableView • Protocol NSFetchedResultsControllerDelegate • section “Typical Use”: there’s the code found in template • connected to a Context: if there are changes of any object inside that context it receives a notification and updates automatically
  • 67. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController Context NSManagedObject NSManagedObject NSManagedObject SQLite UITableView NSFetchedResultsController ??? delegate
  • 68. Diego Freniche / @dfreniche / http://www.freniche.com All needed code for NSFetchedResults Cont. • In the Apple Docs!
  • 69. Diego Freniche / http://www.freniche.com Idea: use Mogenerator
  • 70. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Mogenerator created by Jonathan 'Wolf' Rentzsch
  • 71. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Mogenerator (quoting from the web page) • http://rentzsch.github.io/mogenerator/ • generates Objective-C code for your Core Data custom classes • Unlike Xcode, mogenerator manages two classes per entity: one for machines, one for humans • The machine class can always be overwritten to match the data model, with humans’ work effortlessly preserved
  • 72. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Installing mogenerator
  • 73. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Two classes • _MyClass.*: machine generated • *MyClass.*: human edited ! • Never, ever recreate the classes again from the Core Data Model
  • 74. Diego Freniche / http://www.freniche.com #import "_RetroItem.h" ! @interface RetroItem : _RetroItem {} // Custom logic goes here. @end #import "RetroItem.h" ! ! @interface RetroItem () ! // Private interface goes here. ! @end ! ! @implementation RetroItem ! // Custom logic goes here. ! @end Two classes
  • 75. Diego Freniche / http://www.freniche.comDiego Freniche / @dfreniche / http://www.freniche.com Using it • it’s a script, so we can launch it from command line • using iTerm, DTerm, etc. • Best way: to have it inside our project • Create a new Aggregate Target (New Target > Other > Aggregate) • Add Build Phase > Add Run Script ! mogenerator --template-var arc=true -m RetroStuffTracker/ RetroStuffTracker.xcdatamodeld/RetroStuffTracker.xcdatamodel/
  • 76. Diego Freniche / http://www.freniche.com
  • 77. Diego Freniche / http://www.freniche.com Idea: use Magical Record
  • 78. Diego Freniche / http://www.freniche.com Magical Record Demo Warning: really bad code ahead!
  • 79. Diego Freniche / http://www.freniche.com Magical record != avoid Core Data at all costs • Just a bunch of categories to help you write less code • You have to know your sh*t • CocoaPods friendly • Ideal: use Unit testing + Mogenerator + CocoaPods + Magical Record • My point: 7 people, 7 ideas, all great • all different
  • 80. Diego Freniche / http://www.freniche.com Idea: using asserts to check threads
  • 81. Diego Freniche / http://www.freniche.com Asserts • Check if we are running UI code in the UI Thread • Check if we are NOT running Core Data code in the UI Thread ! #ifndef  CDHelloWord_DFThreadAsserts_h   #define  CDHelloWord_DFThreadAsserts_h   ! #define  DF_ASSERT_MAIN_THREAD  [NSThread  isMainThread]?:(NSLog(@"NOT  IN  MAIN  THREAD"),abort())   #define  DF_ASSERT_NOT_MAIN_THREAD  ![NSThread  isMainThread]?:(NSLog(@"IN  MAIN  THREAD,  BUT  NOT  EXPECTED"),abort())   ! ! #endif  
  • 82. Diego Freniche / http://www.freniche.com Idea: create a common UITableView/Core data class
  • 83.
  • 85. Diego Freniche / @dfreniche / http://www.freniche.com Attributions • http://www.flickr.com/photos/paldies/85684217/ • http://www.flickr.com/photos/56380734@N05/6808753611/ • http://www.flickr.com/photos/msimdottv/4339697089/ • http://www.flickr.com/photos/mobilestreetlife/4179063482/ • http://www.flickr.com/photos/owldreams/4428782193/ • http://www.flickr.com/photos/miss_pupik/73160522/ • http://kfannerd713.deviantart.com/art/UNICORN-PUKING-RAINBOWS-WHAAAA-152117816 • http://www.flickr.com/photos/wwworks/4759535950/ • http://www.flickr.com/photos/barto/28135419/sizes/l/in/photolist-3ucFr-7aiwZ-aqWUu-bLebi-cDeVC-jt2YW-jWW1t-kQ25f-m86XP-swafK-yHMbE-yHMcc-yHMda-