10. What you need (checklist)
• a Mac with OS X capable of running Xcode 4.6.1
• last Xcode 4 installed 4.6.1
• You can also use prerelease software, if you are a registered Apple developer.
No support then, sorry :-D
• SimPholders installed: http://simpholders.com
• SQLLite database browser: http://sqlitebrowser.sourceforge.net
• (optional) set $HOME/Library folder visible, using (from a Terminal)
11. Diego Freniche / http://www.freniche.com
Core Data: developer’s first impression
12. Diego Freniche / http://www.freniche.com
Core Data: developer’s first impression
14. Diego Freniche / http://www.freniche.com
Core Data in 547 easy steps slide 6/320
15. 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
16. 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
17. Diego Freniche / @dfreniche / http://www.freniche.com
To get the most out of Core Data
• KVC, KVO
• ARC, memory management
• delegate & MVC patterns
• singletons are evil (more or less)
18. Diego Freniche / @dfreniche / http://www.freniche.com
Core Data Hello World!
19. Diego Freniche / @dfreniche / http://www.freniche.com
The Problem
• Objet - Relational impedance
• SQL: 70s/80s
• OOP: 80s-
20. Diego Freniche / @dfreniche / http://www.freniche.com
Exhibit 1: composition
Person
+name: String
+idCard: idCard
+bankAccout: bankAccount
21. Diego Freniche / @dfreniche / http://www.freniche.com
Exhibit 1: composition
Person
+name: String
+idCard: idCard
+bankAccout: bankAccount
idCard
+number: int
+letter: char
+checkLetter()
22. 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()
23. 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
24. 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 ¿?
25. Diego Freniche / @dfreniche / http://www.freniche.com
Employee
+empNumber: int
Person
+name: String
+idCard: idCard
Exhibit 2: inheritance
26. Diego Freniche / @dfreniche / http://www.freniche.com
Employee
+empNumber: int
Person
+name: String
+idCard: idCard
Exhibit 2: inheritance
Politician
+moneyTaken: double
27. Diego Freniche / @dfreniche / http://www.freniche.com
Employee
+empNumber: int
Person
+name: String
+idCard: idCard
Exhibit 2: inheritance
Hyena
Politician
+moneyTaken: double
28. 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
29. Diego Freniche / @dfreniche / http://www.freniche.com
Relational World
• tables
• cartesian products
• rows/ columns
• normal forms
• Objects
• object collections
• composition
• inheritance
OO World
30. Diego Freniche / @dfreniche / http://www.freniche.com
Relational World
• tables
• cartesian products
• rows/ columns
• normal forms
• Objects
• object collections
• composition
• inheritance
OO World
31. 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
32. Diego Freniche / @dfreniche / http://www.freniche.com
The Core Data Stack
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
33. Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Context
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
34. Diego Freniche / @dfreniche / http://www.freniche.com
Our Model
NSManagedObjectContext
NSManagedObject
NSManagedObject
NSManagedObject
NSManagedObject
NSObject
PersistedIn memory only
35. 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 save:
• Our model’s objects are Managed Objects.
• The MOC needs a Persistent Store Coordinator to save the object graph in
persistent store.
36. Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Model
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
37. 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)
38. Diego Freniche / @dfreniche / http://www.freniche.com
Managed Object Model
Managed Object Context
Persistent Store Coordinator
Persistent Object Store
Managed Object Model
39. 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
Coordinator: serializes operations
40. 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
41. Diego Freniche / @dfreniche / http://www.freniche.com
SQL in SQLite
• http://sqlite.org/lang.html
• We can see generated SQL: -com.apple.CoreData.SQLDebug 1
• Schemes > Edit Scheme > Test > Arguments
44. 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...
45. 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...
46. 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,...
47. 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
48. 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
50. 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
51. Diego Freniche / @dfreniche / http://www.freniche.com
Entities Design
• Always add field order
• Try to create a good UML diagram at first
• Have an NSString constant with every Entity’s name inside .h
52. 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)
53. Diego Freniche / @dfreniche / http://www.freniche.com
Extend NSManagedObject
• overwrite init to call designated initializer
55. 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
56. 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;
57. Diego Freniche / @dfreniche / http://www.freniche.com
Validator for operations
• First thing: must call [super ...]
• Useful to check business rules (using several properties)
58. 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
59. Diego Freniche / @dfreniche / http://www.freniche.com
Support for KVO
• Good for Faults
60. Diego Freniche / @dfreniche / http://www.freniche.com
Support for KVO
• Good for Faults
- (void)willAccessValueForKey:(NSString *)key
61. Diego Freniche / @dfreniche / http://www.freniche.com
Inserting Entities (INSERT INTO)
insertNewObjectForEntityForName context save
Context
62. Diego Freniche / @dfreniche / http://www.freniche.com
Inserting Entities (INSERT INTO)
// using NSEntityDescription. Pass: entity name and context
[NSEntityDescription insertNewObjectForEntityForName:@”MyEntity” inManagedObjectContext:context];
[retroItem setValue:@"Spectrum 48K" forKey:@"name"];
[retroItem setValue:@100.00 forKey:@"acquisitionCost"];
[retroItem setValue:[NSDate new] forKey:@"dateAcquired"];
insertNewObjectForEntityForName context save
Context
63. 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
64. Diego Freniche / @dfreniche / http://www.freniche.com
Step by Step fetch (Select)
1
2
3
4
5
6
66. 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:
67. 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.
71. 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
72. 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:
75. 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
76. Diego Freniche / @dfreniche / http://www.freniche.com
NSFetchedResultsController
SQLite
UITableView