ActiveResourceKit  v1.2 (498.0)
 All Classes Files Functions Variables Typedefs Enumerator Properties Macros Pages
ActiveResourceKit.h
Go to the documentation of this file.
1 /* ActiveResourceKit ActiveResourceKit.h
2  *
3  * Copyright © 2011, 2012, Roy Ratcliffe, Pioneering Software, United Kingdom
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the “Software”), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
16  * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
18  * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
19  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  ******************************************************************************/
24 
37 
40 
45 
46 /*!
47  * @mainpage Active Resource Kit
48  *
49  * What can you do with Active Resource Kit? Active Resource Kit is yet-another
50  * RESTful framework. There are others. But Active Resource Kit has a number of
51  * distinct features.
52  * 1. It mirrors the Rails Active Resource gem closely. The interface and
53  * implementation remain as faithful as an Objective-C implementation can
54  * reasonably be to the Ruby-based originals.
55  * 2. It offers a very high-level interface to RESTful resources using Core
56  * Data. You can access remote resources just as if they were in a local Core
57  * Data store. The implementation uses the new Core Data @c NSIncrementalStore
58  * API to merge the two dissimilar interfaces.
59  * 3. It only has Foundation and Core Data as underlying dependencies. Although
60  * it has two immediate dependencies, Active Model Kit and Active Support Kit
61  * which fall under the same umbrella framework, Apple's Foundation and Core
62  * Data kits form the only @em external dependencies. The implementation employs
63  * only the Foundation framework for network access.
64  * 4. The framework supports various concurrency models when interacting with
65  * remote resources: these are the same models offered by Apple's Foundation @c
66  * NSURLConnection class, i.e. delegated URL connections, synchronous loading or
67  * queued loading. You can configure according to your requirements on a
68  * resource-by-resource basis.
69  * 5. There are no swizzles or other non-standard Objective-C tricks. The
70  * framework makes extensive use of C blocks for handling completions for both
71  * asynchronous and synchronous interfaces; this simply follows the pattern set
72  * by Apple in their URL connection API.
73  *
74  * @section setting_up Setting Up an Active Resource-Based Core Data Stack
75  *
76  * This is easy to do. Just follow the usual Core Data-prescribed procedure:
77  * load the model, load the coordinator with the model, add the store to the
78  * coordinator, and finally attach the coordinator to the context.
79  *
80  * See example below. There are some things to especially notice. First, the
81  * persistent store type specifies the @c ARIncrementalStore type. The URL
82  * specifies the remote resource, its protocol, host and path. Protocol can be
83  * @c http, or @c https if you want secure transport. The path can specify the
84  * site root, i.e. an empty or single-slash path, or can also include a sub-path
85  * nested within the remote site. The client-side data model must correspond to
86  * the remote's RESTful interface. The Active Resource incremental store
87  * utilises the client-side data model in order to deduce the entities, their
88  * properties and relationships. Core Data itself requires a valid data model.
89  *
90  * @code
91  * NSBundle *bundle = [NSBundle bundleForClass:[self class]];
92  * NSURL *modelURL = [bundle URLForResource:@"MyCoreDataModel" withExtension:@"momd"];
93  * NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
94  * NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
95  *
96  * NSError *__autoreleasing error = nil;
97  * NSPersistentStore *store = [coordinator addPersistentStoreWithType:[ARIncrementalStore storeType]
98  * configuration:nil
99  * URL:[NSURL URLWithString:@"http://localhost:3000"]
100  * options:nil
101  * error:&error];
102  * // <-- error handling goes here
103  *
104  * NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
105  * [context setPersistentStoreCoordinator:coordinator];
106  * [self setContext:context];
107  * @endcode
108  *
109  * Note that this excerpt uses Automatic Reference Counting, hence the @c
110  * __autoreleasing specifier for the error pointer. Notice the blatant lack of
111  * manual auto-releasing.
112  *
113  * @section accessing_resources Accessing Resources
114  *
115  * You can then access resources using @em only Core Data.
116  *
117  * @code
118  * NSError *__autoreleasing error = nil;
119  * NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
120  * NSArray *people = [[self context] executeFetchRequest:request error:&error];
121  * for (NSManagedObject *person in people)
122  * {
123  * NSString *name = [person valueForKey:@"name"];
124  * NSLog(@"person named %@", name);
125  * }
126  * @endcode
127  *
128  * You ask Core Data for the Person entities. The answer is a collection of
129  * managed object representing each Person. You access attributes on the objects
130  * using standard Cocoa key-value coding. However, underneath the hood, the
131  * Active Resource incremental store has enacted a RESTful GET request at
132  * http://localhost:3000/people.json, decoding and caching the active resources
133  * at the client side.
134  *
135  * At the other side of the connection (assuming your server runs on Rails; it
136  * does not need to be Rails but can be any conforming RESTful interface) you
137  * will see a GET request in the server log, as follows. Some details elided.
138  * @code
139  * Started GET "/people.json" for 127.0.0.1 at …
140  * Processing by PeopleController#index as JSON
141  * Person Load (0.2ms) SELECT "people".* FROM "people"
142  * Completed 200 OK in 5ms (Views: 3.8ms | ActiveRecord: 0.2ms)
143  * @endcode
144  *
145  * @subsection inserting_resources Inserting Resources
146  *
147  * This just becomes fuss-free:
148  * @code
149  * NSError *__autoreleasing error = nil;
150  * NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:[self context]];
151  * [person setValue:@"Roy Ratcliffe" forKey:@"name"];
152  * BOOL yes = [[self context] save:&error];
153  * @endcode
154  * And on the server side becomes a familiar POST request:
155  * @code
156  * Started POST "/people.json" for 127.0.0.1 at …
157  * Processing by PeopleController#create as JSON
158  * Parameters: {"person"=>{"name"=>"Roy Ratcliffe"}}
159  * (0.1ms) begin transaction
160  * SQL (0.4ms) INSERT INTO "people" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", …], ["name", "Roy Ratcliffe"], ["updated_at", …]]
161  * (2.3ms) commit transaction
162  * Completed 201 Created in 5ms (Views: 0.8ms | ActiveRecord: 2.8ms)
163  * @endcode
164  *
165  * @subsection deleting_resources Deleting Resources
166  *
167  * Again, just very simply:
168  * @code
169  * NSError *__autoreleasing error = nil;
170  * [[self context] deleteObject:person];
171  * BOOL yes = [[self context] save:&error];
172  * @endcode
173  * And the server responds:
174  * @code
175  * Started DELETE "/people/16.json" for 127.0.0.1 at …
176  * Processing by PeopleController#destroy as JSON
177  * Parameters: {"id"=>"16"}
178  * Person Load (0.1ms) SELECT "people".* FROM "people" WHERE "people"."id" = ? LIMIT 1 [["id", "16"]]
179  * …
180  * SQL (0.3ms) DELETE FROM "people" WHERE "people"."id" = ? [["id", 16]]
181  * …
182  * Completed 200 OK in 15ms (ActiveRecord: 12.7ms)
183  * @endcode
184  *
185  * @subsection forming_associations Forming Associations
186  *
187  * You can conveniently form associations between objects and their remote
188  * resources using only the Core Data interface.
189  *
190  * The following demonstrates what happens when you instantiate two entities and
191  * wire them up entirely at the client side first. Lets say you have a post and
192  * comment model; posts have many comments, a one post to many comments
193  * association. The following initially creates a post with one comment.
194  *
195  * @code
196  * NSManagedObject *post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:[self context]];
197  * NSManagedObject *comment = [NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:[self context]];
198  *
199  * // Set up attributes for the post and the comment.
200  * [post setValue:@"De finibus bonorum et malorum" forKey:@"title"];
201  * [post setValue:@"Non eram nescius…" forKey:@"body"];
202  * [comment setValue:@"Quae cum dixisset…" forKey:@"text"];
203  *
204  * // Form the one-post-to-many-comments association.
205  * [comment setValue:post forKey:@"post"];
206  *
207  * // Send it all to the server.
208  * NSError *__autoreleasing error = nil;
209  * [[self context] save:&error];
210  * @endcode
211  *
212  * It constructs a new post, a new comment and their relationship within the
213  * client at first. Then it saves the context in order to transfer the objects and
214  * their relationship to the remote server.
215  *
216  * Thereafter, you can throw away the comment and refetch it by dereferencing the
217  * post's "comments" relationship. The following extract pulls out each text field
218  * from the comments based on a given post.
219  *
220  * @code
221  * NSMutableArray *comments = [NSMutableArray array];
222  * for (NSManagedObject *comment in [post valueForKey:@"comments"])
223  * {
224  * [comments addObject:[comment valueForKey:@"text"]];
225  * }
226  * [[comments objectAtIndex:0] rangeOfString:@"Quae cum dixisset"].location != NSNotFound;
227  * @endcode
228  */