Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 280 lines (159 sloc) 14.246 kB
b1314b7 @casademora File reorg, updating the README
casademora authored
1 # ![Awesome](https://github.com/magicalpanda/magicalpanda.github.com/blob/master/images/awesome_logo_small.png?raw=true) MagicalRecord
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
b1314b7 @casademora File reorg, updating the README
casademora authored
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.
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
6
7 > *- [Wikipedia]("http://en.wikipedia.org/wiki/Active_record_pattern")*
8
468b2d1 @casademora Updating threading instructions
casademora authored
9 MagicalRecord 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
38515e7 @casademora Minor Readme Updates
casademora authored
15
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
16 # Installation
17
8c3540b @casademora Minor Readme Updates
casademora authored
18 1. In your XCode Project, drag the *MagicalRecord* folder (under the main folder) into your project.
b9e3546 @casademora Updating documentation
casademora authored
19 2. Add *CoreData+MagicalRecord.h* file to your PCH file or your AppDelegate file.
8c3540b @casademora Minor Readme Updates
casademora authored
20 3. Optionally precees the *CoreData+MagicalRecord.h* import with `#define MR_SHORTHAND` to your PCH file if you want to use MagicalRecord methods without the *MR_prefix* like `findAll` instead of `MR_findAll`
b1314b7 @casademora File reorg, updating the README
casademora authored
21 4. Start writing code!
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
22
b1314b7 @casademora File reorg, updating the README
casademora authored
23 # Notes
8c3540b @casademora Minor Readme Updates
casademora authored
24 ## Third Party Blog Entries
25 The following blog entries highlight how to install and use aspects of Magical Record.
26
27 * [How to make Programming with Core Data Pleasant](http://yannickloriot.com/2012/03/magicalrecord-how-to-make-programming-with-core-data-pleasant/)
28 * [Using Core Data with MagicalRecord](http://ablfx.com/blog/2012/03/using-coredata-magicalrecord/)
29 * [Super Happy Easy Fetching in Core Data](http://www.cimgf.com/2011/03/13/super-happy-easy-fetching-in-core-data/)
30 * [Core Data and Threads, without the Headache](http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/)
31 * [Unit Testing with Core Data](http://www.cimgf.com/2012/05/15/unit-testing-with-core-data/)
32
33 ## Twitter
34 Follow [@MagicalRecord](http://twitter.com/magicalrecord) on twitter to stay up to date on twitter with the lastest updates to MagicalRecord and for basic support
35
36 ## Updating to 2.0
37
38 MagicalRecord 2.0 is considered a major update since there were some class and API refactorings that will effect previous installations of MagicalRecord in your code. The most straight forward change is that *MagicalRecordHelpers* and *MRCoreDataAction* have both been replaced with a single class, *MagicalRecord*.
39
b1314b7 @casademora File reorg, updating the README
casademora authored
40 ## ARC Support
d66b419 @casademora Updated some docs
casademora authored
41
b1314b7 @casademora File reorg, updating the README
casademora authored
42 MagicalRecord fully supports ARC out of the box, there is no configuration necessary.
468b2d1 @casademora Updating threading instructions
casademora authored
43 The last version to support manually managed memory is 1.8.3, and is available from the downloads page, or by switching to the 1.8.3 tag in the source.
b1314b7 @casademora File reorg, updating the README
casademora authored
44
45 ## Nested Contexts
46
8c3540b @casademora Minor Readme Updates
casademora authored
47 New in Core Data is support for related contexts. This is a super neat, and super fast feature. However, writing a wrapper that supports both is, frankly, more work that it's worth. However, the 1.8.3 version will be the last version that has dual support, and going forward, MagicalRecord will only work with the version of Core Data that has supports nested managed object contexts.
d66b419 @casademora Updated some docs
casademora authored
48
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
49 # Usage
50
51 ## Setting up the Core Data Stack
52
1a4f8d6 @casademora Removing references to ActiveRecord, renaming to MagicalRecord
casademora authored
53 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.
4e3f9fb @yas375 fixed some markdown issues with `*` instead of `\*`
yas375 authored
54 Next, somewhere in your app delegate, in either the applicationDidFinishLaunching:(UIApplication \*) withOptions:(NSDictionary \*) method, or awakeFromNib, use **one** of the following setup calls with the **MagicalRecord** class:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
55
56 + (void) setupCoreDataStack;
57 + (void) setupAutoMigratingDefaultCoreDataStack;
58 + (void) setupCoreDataStackWithInMemoryStore;
59 + (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName;
60 + (void) setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(NSString *)storeName;
cce797d @casademora Update threading instructions
casademora authored
61
b9e3546 @casademora Updating documentation
casademora authored
62 Each call instantiates one of each piece of the Core Data stack, and provides getter and setter methods for these instances. These well known instances to MagicalRecord, and are recognized as "defaults".
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
63
64 And, before your app exits, you can use the clean up method:
65
468b2d1 @casademora Updating threading instructions
casademora authored
66 [MagicalRecord cleanUp];
9dddc5d @emrosenf [README] Provide iCloud details
emrosenf authored
67
68 ## iCloud Support
69
468b2d1 @casademora Updating threading instructions
casademora authored
70 Apps built for iOS5+ and OSX Lion 10.7.2+ can take advantage of iCloud to sync Core Data stores. To implement this functionality with MagicalRecord, use **one** of the following setup calls instead of those listed in the previous section:
9dddc5d @emrosenf [README] Provide iCloud details
emrosenf authored
71
051c8fb Update README.md
Evan Rosenfeld authored
72 + (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore;
73 + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent;
74 + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent completion:(void(^)(void))completion;
9dddc5d @emrosenf [README] Provide iCloud details
emrosenf authored
75
adad524 Update README.md
Evan Rosenfeld authored
76 For further details, and to ensure that your application is suitable for iCloud, please see [Apple's iCloud Notes](https://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html).
77
4e3f9fb @yas375 fixed some markdown issues with `*` instead of `\*`
yas375 authored
78 In particular note that the first helper method, + (void) setupCoreDataStackWithiCloudContainer:(NSString \*)icloudBucket localStoreNamed:(NSString \*)localStore, automatically generates the **NSPersistentStoreUbiquitousContentNameKey** based on your application's Bundle Identifier.
adad524 Update README.md
Evan Rosenfeld authored
79
80 If you are managing multiple different iCloud stores it is highly recommended that you use one of the other helper methods to specify your own **contentNameKey**
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
81
82 ### Default Managed Object Context
83
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
84 When using Core Data, you will deal with two types of objects the most: *NSManagedObject* and *NSManagedObjectContext*. MagicalRecord gives you a place for a default NSManagedObjectContext for use within your app. This is great for single threaded apps. You can easily get to this default context by calling:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
85
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
86 [NSManagedObjectContext MR_defaultContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
87
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
88 This context will be used if a find or request method (described below) is not specifying a specific context using the **inContext:** method overload.
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
89
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
90 If you need to create a new Managed Object Context for use in other threads, based on the default persistent store that was creating using one of the setup methods, use:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
91
b1314b7 @casademora File reorg, updating the README
casademora authored
92 NSManagedObjectContext *myNewContext = [NSManagedObjectContext MR_context];
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
93
94 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.
95
96 And, if you want to make *myNewContext* the default for all fetch requests on the main thread:
b9e3546 @casademora Updating documentation
casademora authored
97
b1314b7 @casademora File reorg, updating the README
casademora authored
98 [NSManagedObjectContext MR_setDefaultContext:myNewContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
99
468b2d1 @casademora Updating threading instructions
casademora authored
100 MagicalRecord also has a helper method to hold on to a Managed Object Context in a thread's threadDictionary. This lets you access the correct NSManagedObjectContext instance no matter which thread you're calling from. This methods is:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
101
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
102 [NSManagedObjectContext MR_contextForCurrentThread];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
103
b9e3546 @casademora Updating documentation
casademora authored
104 **It is *highly* recommended that the default context is created and set using the main thread**
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
105
106 ### Fetching
107
108 #### Basic Finding
b9e3546 @casademora Updating documentation
casademora authored
109
110 Most methods in MagicalRecord 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
111
feffba8 @tonyxiao Update Readme.md to reflect recent changes, especially the MR_SHORTHA…
tonyxiao authored
112 //In order for this to work you need to add "#define MR_SHORTHAND" to your PCH file
b1314b7 @casademora File reorg, updating the README
casademora authored
113 NSArray *people = [Person MR_findAll];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
114
feffba8 @tonyxiao Update Readme.md to reflect recent changes, especially the MR_SHORTHA…
tonyxiao authored
115 // Otherwise you can use the longer, namespaced version
116 NSArray *people = [Person MR_findAll];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
117
118 Or, to have the results sorted by a property:
119
b1314b7 @casademora File reorg, updating the README
casademora authored
120 NSArray *peopleSorted = [Person MR_findAllSortedByProperty:@"LastName" ascending:YES];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
121
26d74ec @casademora Adding aggregate operation support submitted from Duane Fields. Thank…
casademora authored
122 Or, to have the results sorted by multiple properties:
123
b1314b7 @casademora File reorg, updating the README
casademora authored
124 NSArray *peopleSorted = [Person MR_findAllSortedByProperty:@"LastName,FirstName" ascending:YES];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
125
126 If you have a unique way of retrieving a single object from your data store, you can get that object directly:
127
b1314b7 @casademora File reorg, updating the README
casademora authored
128 Person *person = [Person MR_findFirstByAttribute:@"FirstName" withValue:@"Forrest"];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
129
130 #### Advanced Finding
131
132 If you want to be more specific with your search, you can send in a predicate:
133
134 NSArray *departments = [NSArray arrayWithObjects:dept1, dept2, ..., nil];
135 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
136
b1314b7 @casademora File reorg, updating the README
casademora authored
137 NSArray *people = [Person MR_findAllWithPredicate:peopleFilter];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
138
b9e3546 @casademora Updating documentation
casademora authored
139 #### Returning an NSFetchRequest
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
140
141 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
142
b1314b7 @casademora File reorg, updating the README
casademora authored
143 NSArray *people = [Person MR_fetchAllWithPredicate:peopleFilter];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
144
145 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.
146
b9e3546 @casademora Updating documentation
casademora authored
147 #### Customizing the Request
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
148
149 NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@"Department IN %@", departments];
150
b1314b7 @casademora File reorg, updating the README
casademora authored
151 NSFetchRequest *peopleRequest = [Person MR_requestAllWithPredicate:peopleFilter];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
152 [peopleRequest setReturnsDistinctResults:NO];
153 [peopleRequest setReturnPropertiesNamed:[NSArray arrayWithObjects:@"FirstName", @"LastName", nil]];
154 ...
155
b1314b7 @casademora File reorg, updating the README
casademora authored
156 NSArray *people = [Person MR_executeFetchRequest:peopleRequest];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
157
158 #### Find the number of entities
159
160 You can also perform a count of entities in your Store, that will be performed on the Store
161
b1314b7 @casademora File reorg, updating the README
casademora authored
162 NSNumber *count = [Person MR_numberOfEntities];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
163
164 Or, if you're looking for a count of entities based on a predicate or some filter:
165
b1314b7 @casademora File reorg, updating the README
casademora authored
166 NSNumber *count = [Person MR_numberOfEntitiesWithPredicate:...];
b9e3546 @casademora Updating documentation
casademora authored
167
168 There are also counterpart methods which return NSUInteger rather than NSNumbers:
169
170 * countOfEntities
171 * countOfEntitiesWithContext:(NSManagedObjectContext *)
172 * countOfEntitiesWithPredicate:(NSPredicate *)
173 * countOfEntitiesWithPredicate:(NSPredicate *) inContext:(NSManagedObjectContext *)
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
174
26d74ec @casademora Adding aggregate operation support submitted from Duane Fields. Thank…
casademora authored
175 #### Aggregate Operations
176
177 NSPredicate *prediate = [NSPredicate predicateWithFormat:@"diaryEntry.date == %@", today];
b1314b7 @casademora File reorg, updating the README
casademora authored
178 int totalFat = [[CTFoodDiaryEntry MR_aggregateOperation:@"sum:" onAttribute:@"fatColories" withPredicate:predicate] intValue];
179 int fattest = [[CTFoodDiaryEntry MR_aggregateOperation:@"max:" onAttribute:@"fatColories" withPredicate:predicate] intValue];
26d74ec @casademora Adding aggregate operation support submitted from Duane Fields. Thank…
casademora authored
180
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
181 #### Finding from a different context
182
183 All find, fetch and request methods have an inContext: method parameter
184
185 NSManagedObjectContext *someOtherContext = ...;
186
b1314b7 @casademora File reorg, updating the README
casademora authored
187 NSArray *peopleFromAnotherContext = [Person MR_findAllInContext:someOtherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
188
189 ...
190
b1314b7 @casademora File reorg, updating the README
casademora authored
191 Person *personFromContext = [Person MR_findFirstByAttribute:@"lastName" withValue:@"Gump" inContext:someOtherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
192
193 ...
194
b1314b7 @casademora File reorg, updating the README
casademora authored
195 NSUInteger count = [Person MR_numberOfEntitiesWithContext:someOtherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
196
197
198 ## Creating new Entities
199
200 When you need to create a new instance of an Entity, use:
201
b1314b7 @casademora File reorg, updating the README
casademora authored
202 Person *myNewPersonInstance = [Person MR_createEntity];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
203
204 or, to specify a context:
205
206 NSManagedObjectContext *otherContext = ...;
207
b1314b7 @casademora File reorg, updating the README
casademora authored
208 Person *myPerson = [Person MR_createInContext:otherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
209
210
211 ## Deleting Entities
212
213 To delete a single entity:
214
215 Person *p = ...;
b1314b7 @casademora File reorg, updating the README
casademora authored
216 [p MR_deleteEntity];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
217
218 or, to specify a context:
219
220 NSManagedObjectContext *otherContext = ...;
221 Person *deleteMe = ...;
222
b1314b7 @casademora File reorg, updating the README
casademora authored
223 [deleteMe MR_deleteInContext:otherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
224
225 There is no delete *All Entities* or *truncate* operation in core data, so one is provided for you with Active Record for Core Data:
226
b1314b7 @casademora File reorg, updating the README
casademora authored
227 [Person MR_truncateAll];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
228
229 or, with a specific context:
230
231 NSManagedObjectContext *otherContext = ...;
b1314b7 @casademora File reorg, updating the README
casademora authored
232 [Person MR_truncateAllInContext:otherContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
233
234 ## Performing Core Data operations on Threads
235
468b2d1 @casademora Updating threading instructions
casademora authored
236 MagicalRecord also provides some handy methods to set up background context for use with threading. The background saving operations are inspired by the UIView animation block methods, with few minor differences:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
237
468b2d1 @casademora Updating threading instructions
casademora authored
238 * The block in which you add your data saving code will never be on the main thread.
239 * a single NSManagedObjectContext is provided for your operations.
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
240
468b2d1 @casademora Updating threading instructions
casademora authored
241 For example, if we have Person entity, and we need to set the firstName and lastName fields, this is how you would use MagicalRecord to setup a background context for your use:
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
242
cce797d @casademora Update threading instructions
casademora authored
243 Person *person = ...;
468b2d1 @casademora Updating threading instructions
casademora authored
244 [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
245
246 Person *localPerson = [person MR_inContext:localContext];
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
247
468b2d1 @casademora Updating threading instructions
casademora authored
248 localPerson.firstName = @"John";
249 localPerson.lastName = @"Appleseed";
250
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
251 }];
252
468b2d1 @casademora Updating threading instructions
casademora authored
253 In this method, the specified block 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
254
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
255 To perform an action after this save block is completed, you can fill in a completion block:
256
257 Person *person = ...;
468b2d1 @casademora Updating threading instructions
casademora authored
258 [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
259
260 Person *localPerson = [person MR_inContext:localContext];
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
261
468b2d1 @casademora Updating threading instructions
casademora authored
262 localPerson.firstName = @"John";
263 localPerson.lastName = @"Appleseed";
264
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
265 } completion:^{
266
267 self.everyoneInTheDepartment = [Person findAll];
468b2d1 @casademora Updating threading instructions
casademora authored
268
5470cc6 @casademora Made the default managed object context section more clear.
casademora authored
269 }];
270
271 This completion block is called on the main thread (queue), so this is also safe for triggering UI updates.
272
d66b419 @casademora Updated some docs
casademora authored
273 # Data Import
274
38515e7 @casademora Minor Readme Updates
casademora authored
275 MagicalRecord will now import data from NSObjects into your Core Data store. [Documentation](https://github.com/magicalpanda/MagicalRecord/wiki/Data-Import) for this feature is forthcoming and will be available in full by May 25, 2012.
dc6ab2c @casademora updated readme, changed to markdown
casademora authored
276
277 # Extra Bits
38515e7 @casademora Minor Readme Updates
casademora authored
278 This Code is released under the MIT License by [Magical Panda Software, LLC](http://www.magicalpanda.com). We love working on iOS and Mac apps for you!
b1314b7 @casademora File reorg, updating the README
casademora authored
279 There is no charge for Awesome.
Something went wrong with that request. Please try again.