Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 213 lines (116 sloc) 9.292 kB
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
1 # MagicalRecord for Core Data
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
2
3 In software engineering, the active record pattern is a design pattern found in software that stores its data in relational databases. It was named by Martin Fowler in his book Patterns of Enterprise Application Architecture. The interface to such an object would include functions such as Insert, Update, and Delete, plus properties that correspond more-or-less directly to the columns in the underlying database table.
4
5 > Active record is an approach to accessing data in a database. A database table or view is wrapped into a class; thus an object instance is tied to a single row in the table. After creation of an object, a new row is added to the table upon save. Any object loaded gets its information from the database; when an object is updated, the corresponding row in the table is also updated. The wrapper class implements accessor methods or properties for each column in the table or view.
6
7 > *- [Wikipedia]("http://en.wikipedia.org/wiki/Active_record_pattern")*
8
6992aeb @casademora Some working tests verifying entity relationships are set properly
casademora authored
9 Magical Record for Core Data was inspired by the ease of Ruby on Rails' Active Record fetching. The goals of this code are:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
10
11 * Clean up my Core Data related code
12 * Allow for clear, simple, one-line fetches
13 * Still allow the modification of the NSFetchRequest when request optimizations are needed
14
15 # Installation
16
6992aeb @casademora Some working tests verifying entity relationships are set properly
casademora authored
17 - In your XCode Project, add all the .h and .m files from the Source folder into your project.
d66b419 @casademora Updated some docs
casademora authored
18 - Add *CoreData+MagicalRecord.h* file to your PCH file or your AppDelegate file.
cce797d @casademora Update threading instructions
casademora authored
19 - Start writing code! ... There is no step 3!
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
20
d66b419 @casademora Updated some docs
casademora authored
21 # ARC Support
22
23 As of tag 1.5, ARC is supported. I am not aware of any way to provide a backward compatible solution and still maintain only 1 codebase, so MagicalRecord will be ARC compliant from here on in.
24
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
25 # Usage
26
27 ## Setting up the Core Data Stack
28
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
29 To get started, first, import the header file *CoreData+MagicalRecord.h* in your project's pch file. This will allow a global include of all the required headers.
30 Next, somewhere in your app's startup, say in the applicationDidFinishLaunching:(UIApplication *) withOptions:(NSDictionary *) method, use one of the following setup calls with the MagicalRecordHelpers class:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
31
32 + (void) setupCoreDataStack;
33 + (void) setupAutoMigratingDefaultCoreDataStack;
34 + (void) setupCoreDataStackWithInMemoryStore;
35 + (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName;
36 + (void) setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(NSString *)storeName;
cce797d @casademora Update threading instructions
casademora authored
37
38 - or -
39
40 Simply start creating, fetching and updating objects. A default stack will be created for you automatically if one does not already exist. It's magical :)
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
41
42 And, before your app exits, you can use the clean up method:
43
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
44 [MagicalRecordHelpers cleanUp];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
45
46 ### Default Managed Object Context
47
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
48 When using Core Data, you will deal with two types of objects the most: NSManagedObject and NSManagedObjectContext. MagicalRecord for Core Data gives you a place for a default NSManagedObjectContext for use within your app. This is great for single threaded apps. If you need to create a new Managed Object Context for use in other threads, based on your single persistent store, use:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
49
50 NSManagedObjectContext *myNewContext = [NSManagedObjectContext context];
51
52
53 This default context will be used for all fetch requests, unless otherwise specified in the methods ending with **inContext:**.
54 If you want to make *myNewContext* the default for all fetch requests on the main thread:
55
56 [NSManagedObjectContext setDefaultContext:myNewContext];
57
58
59 This will use the same object model and persistent store, but create an entirely new context for use with threads other than the main thread.
60
61 **It is recommended that the default context is created and set using the main thread**
62
63 ### Fetching
64
65 #### Basic Finding
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
66 Most methods in the MagicalRecord for Core Data library return an NSArray of results. So, if you have an Entity called Person, related to a Department (as seen in various Apple Core Data documentation), to get all the Person entities from your Persistent Store:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
67
68
69 NSArray *people = [Person findAll];
70
71
72 Or, to have the results sorted by a property:
73
74 NSArray *peopleSorted = [Person findAllSortedByProperty:@"LastName" ascending:YES];
75
76
77 If you have a unique way of retrieving a single object from your data store, you can get that object directly:
78
79 Person *person = [Person findFirstByAttribute:@"FirstName" withValue:@"Forrest"];
80
81 #### Advanced Finding
82
83 If you want to be more specific with your search, you can send in a predicate:
84
85 NSArray *departments = [NSArray arrayWithObjects:dept1, dept2, ..., nil];
86 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
87
88 NSArray *people = [Person findAllWithPredicate:peopleFilter];
89
90 Returning an NSFetchRequest
91
92 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
93
94 NSArray *people = [Person fetchAllWithPredicate:peopleFilter];
95
96 For each of these single line calls, the full stack of NSFetchRequest, NSSortDescriptors and a simple default error handling scheme (ie. logging to the console) is created.
97
98 Customizing the Request
99
100 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
101
102 NSFetchRequest *peopleRequest = [Person requestAllWithPredicate:peopleFilter];
103 [peopleRequest setReturnsDistinctResults:NO];
104 [peopleRequest setReturnPropertiesNamed:[NSArray arrayWithObjects:@"FirstName", @"LastName", nil]];
105 ...
106
107 NSArray *people = [Person executeFetchRequest:peopleRequest];
108
109 #### Find the number of entities
110
111 You can also perform a count of entities in your Store, that will be performed on the Store
112
113 NSUInteger count = [Person numberOfEntities];
114
115 Or, if you're looking for a count of entities based on a predicate or some filter:
116
117 NSUInteger count = [Person numberOfEntitiesWithPredicate:...];
118
119 #### Finding from a different context
120
121 All find, fetch and request methods have an inContext: method parameter
122
123 NSManagedObjectContext *someOtherContext = ...;
124
125 NSArray *peopleFromAnotherContext = [Person findAllInContext:someOtherContext];
126
127 ...
128
129 Person *personFromContext = [Person findFirstByAttribute:@"lastName" withValue:@"Gump" inContext:someOtherContext];
130
131 ...
132
133 NSUInteger count = [Person numberOfEntitiesWithContext:someOtherContext];
134
135
136 ## Creating new Entities
137
138 When you need to create a new instance of an Entity, use:
139
140 Person *myNewPersonInstance = [Person createEntity];
141
142 or, to specify a context:
143
144 NSManagedObjectContext *otherContext = ...;
145
146 Person *myPerson = [Person createInContext:otherContext];
147
148
149 ## Deleting Entities
150
151 To delete a single entity:
152
153 Person *p = ...;
154 [p deleteEntity];
155
156 or, to specify a context:
157
158 NSManagedObjectContext *otherContext = ...;
159 Person *deleteMe = ...;
160
161 [deleteMe deleteInContext:otherContext];
162
163 There is no delete *All Entities* or *truncate* operation in core data, so one is provided for you with Active Record for Core Data:
164
165 [Person truncateAll];
166
167 or, with a specific context:
168
169 NSManagedObjectContext *otherContext = ...;
170 [Person truncateAllInContext:otherContext];
171
172 ## Performing Core Data operations on Threads
173
174 Available only on iOS 4.0 and Mac OS 10.6
175
176 Paraphrasing the [Apple documentation on Core Data and Threading]("http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdConcurrency.html#//apple_ref/doc/uid/TP40003385-SW1"), you should always do the following:
177
178 * Use a new, dedicated NSManagedObjectContext instance for every thread
179 * Use an instance of your NSManagedObjects that is local for the new NSManagedObjectContext
180 * Notify other contexts that the background is updated or saved
181
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
182 The Magical Record library is trying to make these steps more reusable with the following methods:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
183
184 + (void) performSaveDataOperationWithBlock:(CoreDataBlock)block;
185 + (void) performSaveDataOperationInBackgroundWithBlock:(CoreDataBlock)block;
186
187 CoreDataBlock is typedef'd as:
188
189 typedef void (^CoreDataBlock)(NSManagedObjectContext *);
190
191 All the boilerplate operations that need to be done when saving are done in these methods. To use this method from the *main thread*:
192
cce797d @casademora Update threading instructions
casademora authored
193 Person *person = ...;
6992aeb @casademora Some working tests verifying entity relationships are set properly
casademora authored
194 [MRCoreDataAction saveDataInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
cce797d @casademora Update threading instructions
casademora authored
195 Person *localPerson = [person inContext:localContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
196
197 localPerson.firstName = @"Chuck";
198 localPerson.lastName = @"Smith";
199 }];
200
201 In this method, the CoreDataBlock provides you with the proper context in which to perform your operations, you don't need to worry about setting up the context so that it tells the Default Context that it's done, and should update because changes were performed on another thread.
cce797d @casademora Update threading instructions
casademora authored
202
6992aeb @casademora Some working tests verifying entity relationships are set properly
casademora authored
203 All MRCoreDataActions have a dedicated GCD queue on which they operate. This means that throughout your app, you only really have 2 queues (sort of like threads) performing Core Data actions at any one time: one on the main queue, and another on this dedicated GCD queue.
d66b419 @casademora Updated some docs
casademora authored
204
205 # Data Import
206
207 *Experimental*
208
209 MagicalRecord will now import data from NSDictionaries into your Core Data store. This feature is currently under development, and is undergoing updates. Feel free to try it out, add tests and send in your feedback.
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
210
211 # Extra Bits
212 This Code is released under the MIT License by [Magical Panda Software, LLC.](http://www.magicalpanda.com)
Something went wrong with that request. Please try again.