forked from AFNetworking/AFIncrementalStore
/
AFIncrementalStore.h
377 lines (270 loc) · 17.9 KB
/
AFIncrementalStore.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
// AFIncrementalStore.h
//
// Copyright (c) 2012 Mattt Thompson (http://mattt.me)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <CoreData/CoreData.h>
#import "AFNetworking.h"
#import <objc/runtime.h>
@interface NSPersistentStoreRequest (_AFIncrementalStore)
/**
A property set by AFIncrementalStore to uniquely identify a NSFetchRequest or NSSaveChanges request, in order for the AFFetchSaveManager class to correctly identify it via NSNotification, and subsequently fire the appropriate completion block for that request.
@discussion If there is a completion block associated with the NSPersistentStoreRequest, AFFetchSaveManager will have generated this unique identifier upon first dispatch of the request and conveys it to the AFIncrementalStore by attaching it to the `userInfo` dictionary of the NSManagedObjectContext.
*/
@property (readwrite, nonatomic, copy, setter = af_setRequestIdentifier:) NSString *af_requestIdentifier;
@end
static char kAFRequestIdentifierObjectKey;
@implementation NSPersistentStoreRequest (_AFIncrementalStore)
@dynamic af_requestIdentifier;
- (NSString *)af_requestIdentifier {
return (NSString *)objc_getAssociatedObject(self, &kAFRequestIdentifierObjectKey);
}
- (void)af_setRequestIdentifier:(NSString *)requestIdentifier {
objc_setAssociatedObject(self, &kAFRequestIdentifierObjectKey, requestIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
@protocol AFIncrementalStoreDelegate;
@protocol AFIncrementalStoreHTTPClient;
/**
`AFIncrementalStore` is an abstract subclass of `NSIncrementalStore`, designed to allow you to load and save data incrementally to and from a one or more web services.
## Subclassing Notes
### Methods to Override
In a subclass of `AFIncrementalStore`, you _must_ override the following methods to provide behavior appropriate for your store:
- `+type`
- `+model`
Additionally, all `NSPersistentStore` subclasses, and thus all `AFIncrementalStore` subclasses must do `NSPersistentStoreCoordinator +registerStoreClass:forStoreType:` in order to be created by `NSPersistentStoreCoordinator -addPersistentStoreWithType:configuration:URL:options:error:`. It is recommended that subclasses register themselves in their own `+initialize` method.
Optionally, `AFIncrementalStore` subclasses can override the following methods:
- `-executeFetchRequest:withContext:error:`
- `-executeSaveChangesRequest:withContext:error:`
### Methods Not To Be Overridden
Subclasses should not override `-executeRequest:withContext:error`. Instead, override `-executeFetchRequest:withContext:error:` or `-executeSaveChangesRequest:withContext:error:`, which are called by `-executeRequest:withContext:error` depending on the type of persistent store request.
*/
@interface AFIncrementalStore : NSIncrementalStore
///---------------------------------------------
/// @name Accessing Incremental Store Properties
///---------------------------------------------
/**
The HTTP client used to manage requests and responses with the associated web services.
*/
@property (nonatomic, strong) AFHTTPClient <AFIncrementalStoreHTTPClient> *HTTPClient;
/**
The persistent store coordinator used to persist data from the associated web serivices locally.
@discussion Rather than persist values directly, `AFIncrementalStore` manages and proxies through a persistent store coordinator.
*/
@property (readonly) NSPersistentStoreCoordinator *backingPersistentStoreCoordinator;
///-----------------------
/// @name Required Methods
///-----------------------
/**
Returns the string used as the `NSStoreTypeKey` value by the application's persistent store coordinator.
@return The string used to describe the type of the store.
*/
+ (NSString *)type;
/**
Returns the managed object model used by the store.
@return The managed object model used by the store
*/
+ (NSManagedObjectModel *)model;
///-----------------------
/// @name Optional Methods
///-----------------------
/**
*/
- (id)executeFetchRequest:(NSFetchRequest *)fetchRequest
withContext:(NSManagedObjectContext *)context
error:(NSError *__autoreleasing *)error;
/**
*/
- (id)executeSaveChangesRequest:(NSSaveChangesRequest *)saveChangesRequest
withContext:(NSManagedObjectContext *)context
error:(NSError *__autoreleasing *)error;
@end
#pragma mark -
/**
The `AFIncrementalStoreHTTPClient` protocol defines the methods used by the HTTP client to interract with the associated web services of an `AFIncrementalStore`.
*/
@protocol AFIncrementalStoreHTTPClient <NSObject>
///-----------------------
/// @name Required Methods
///-----------------------
/**
Returns an `NSDictionary` or an `NSArray` of `NSDictionaries` containing the representations of the resources found in a response object.
@discussion For example, if `GET /users` returned an `NSDictionary` with an array of users keyed on `"users"`, this method would return the keyed array. Conversely, if `GET /users/123` returned a dictionary with all of the atributes of the requested user, this method would simply return that dictionary.
@param responseObject The response object returned from the server.
@return An `NSDictionary` or an `NSArray` of `NSDictionaries` containing the resource representations.
*/
- (id)representationOrArrayOfRepresentationsFromResponseObject:(id)responseObject;
/**
Returns an `NSDictionary` containing the representations of associated objects found within the representation of a response object, keyed by their relationship name.
@discussion For example, if `GET /albums/123` returned the representation of an album, including the tracks as sub-entities, keyed under `"tracks"`, this method would return a dictionary with an array of representations for those objects, keyed under the name of the relationship used in the model (which is likely also to be `"tracks"`). Likewise, if an album also contained a representation of its artist, that dictionary would contain a dictionary representation of that artist, keyed under the name of the relationship used in the model (which is likely also to be `"artist"`).
@param representation The resource representation.
@param entity The entity for the representation.
@param response The HTTP response for the resource request.
@return An `NSDictionary` containing representations of relationships, keyed by relationship name.
*/
- (NSDictionary *)representationsForRelationshipsFromRepresentation:(NSDictionary *)representation
ofEntity:(NSEntityDescription *)entity
fromResponse:(NSHTTPURLResponse *)response;
/**
Returns the resource identifier for the resource whose representation of an entity came from the specified HTTP response. A resource identifier is a string that uniquely identifies a particular resource among all resource types. If new attributes come back for an existing resource identifier, the managed object associated with that resource identifier will be updated, rather than a new object being created.
@discussion For example, if `GET /posts` returns a collection of posts, the resource identifier for any particular one might be its URL-safe "slug" or parameter string, or perhaps its numeric id. For example: `/posts/123` might be a resource identifier for a particular post.
@param representation The resource representation.
@param entity The entity for the representation.
@param response The HTTP response for the resource request.
@return An `NSString` resource identifier for the resource.
*/
- (NSString *)resourceIdentifierForRepresentation:(NSDictionary *)representation
ofEntity:(NSEntityDescription *)entity
fromResponse:(NSHTTPURLResponse *)response;
/**
Returns the attributes for the managed object corresponding to the representation of an entity from the specified response. This method is used to get the attributes of the managed object from its representation returned in `-representationOrArrayOfRepresentationsFromResponseObject` or `representationsForRelationshipsFromRepresentation:ofEntity:fromResponse:`.
@discussion For example, if the representation returned from `GET /products/123` had a `description` field that corresponded with the `productDescription` attribute in its Core Data model, this method would set the value of the `productDescription` key in the returned dictionary to the value of the `description` field in representation.
@param representation The resource representation.
@param entity The entity for the representation.
@param response The HTTP response for the resource request.
@return An `NSDictionary` containing the attributes for a managed object.
*/
- (NSDictionary *)attributesForRepresentation:(NSDictionary *)representation
ofEntity:(NSEntityDescription *)entity
fromResponse:(NSHTTPURLResponse *)response;
/**
Returns a URL request object for the specified fetch request within a particular managed object context.
@discussion For example, if the fetch request specified the `User` entity, this method might return an `NSURLRequest` with `GET /users` if the web service was RESTful, `POST /endpoint?method=users.getAll` for an RPC-style system, or a request with an XML envelope body for a SOAP webservice.
@param fetchRequest The fetch request to translate into a URL request.
@param context The managed object context executing the fetch request.
@return An `NSURLRequest` object corresponding to the specified fetch request.
*/
- (NSMutableURLRequest *)requestForFetchRequest:(NSFetchRequest *)fetchRequest
withContext:(NSManagedObjectContext *)context;
/**
Returns a URL request object with a given HTTP method for a particular managed object. This method is used in `AFIncrementalStore -newValuesForObjectWithID:withContext:error`.
@discussion For example, if a `User` managed object were to be refreshed, this method might return a `GET /users/123` request.
@param method The HTTP method of the request.
@param objectID The object ID for the specified managed object.
@param context The managed object context for the managed object.
@return An `NSURLRequest` object with the provided HTTP method for the resource corresponding to the managed object.
*/
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
pathForObjectWithID:(NSManagedObjectID *)objectID
withContext:(NSManagedObjectContext *)context;
/**
Returns a URL request object with a given HTTP method for a particular relationship of a given managed object. This method is used in `AFIncrementalStore -newValueForRelationship:forObjectWithID:withContext:error:`.
@discussion For example, if a `Department` managed object was attempting to fulfill a fault on the `employees` relationship, this method might return `GET /departments/sales/employees`.
@param method The HTTP method of the request.
@param relationship The relationship of the specifified managed object
@param objectID The object ID for the specified managed object.
@param context The managed object context for the managed object.
@return An `NSURLRequest` object with the provided HTTP method for the resource or resoures corresponding to the relationship of the managed object.
*/
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
pathForRelationship:(NSRelationshipDescription *)relationship
forObjectWithID:(NSManagedObjectID *)objectID
withContext:(NSManagedObjectContext *)context;
@optional
///-----------------------
/// @name Optional Methods
///-----------------------
/**
*/
- (NSDictionary *)representationOfAttributes:(NSDictionary *)attributes
ofManagedObject:(NSManagedObject *)managedObject;
/**
*/
- (NSMutableURLRequest *)requestForInsertedObject:(NSManagedObject *)insertedObject;
/**
*/
- (NSMutableURLRequest *)requestForUpdatedObject:(NSManagedObject *)updatedObject;
/**
*/
- (NSMutableURLRequest *)requestForDeletedObject:(NSManagedObject *)deletedObject;
/**
Returns whether the client should fetch remote attribute values for a particular managed object. This method is consulted when a managed object faults on an attribute, and will call `-requestWithMethod:pathForObjectWithID:withContext:` if `YES`.
@param objectID The object ID for the specified managed object.
@param context The managed object context for the managed object.
@return `YES` if an HTTP request should be made, otherwise `NO.
*/
- (BOOL)shouldFetchRemoteAttributeValuesForObjectWithID:(NSManagedObjectID *)objectID
inManagedObjectContext:(NSManagedObjectContext *)context;
/**
Returns whether the client should fetch remote relationship values for a particular managed object. This method is consulted when a managed object faults on a particular relationship, and will call `-requestWithMethod:pathForRelationship:forObjectWithID:withContext:` if `YES`.
@param relationship The relationship of the specifified managed object
@param objectID The object ID for the specified managed object.
@param context The managed object context for the managed object.
@return `YES` if an HTTP request should be made, otherwise `NO.
*/
- (BOOL)shouldFetchRemoteValuesForRelationship:(NSRelationshipDescription *)relationship
forObjectWithID:(NSManagedObjectID *)objectID
inManagedObjectContext:(NSManagedObjectContext *)context;
@end
///----------------
/// @name Constants
///----------------
/**
The name of the exception called when `AFIncrementalStore` or a subclass is attempted to be used, without implementing one of the required methods.
*/
extern NSString * const AFIncrementalStoreUnimplementedMethodException;
///--------------------
/// @name Notifications
///--------------------
/**
Posted before an HTTP request operation starts.
The object is the managed object context of the request.
The notification `userInfo` contains the finished request operation, keyed at `AFIncrementalStoreRequestOperationKey`, as well as the associated persistent store request, if applicable, keyed at `AFIncrementalStorePersistentStoreRequestKey`.
*/
extern NSString * const AFIncrementalStoreContextWillFetchRemoteValues;
/**
*/
extern NSString * const AFIncrementalStoreContextWillSaveRemoteValues;
/**
Posted after an HTTP request operation finishes.
The object is the managed object context of the request.
The notification `userInfo` contains the finished request operation, keyed at `AFIncrementalStoreRequestOperationKey`, as well as the associated persistent store request, if applicable, keyed at `AFIncrementalStorePersistentStoreRequestKey`.
*/
extern NSString * const AFIncrementalStoreContextDidFetchRemoteValues;
/**
*/
extern NSString * const AFIncrementalStoreContextDidSaveRemoteValues;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextWillFetchRemoteValues` or `AFIncrementalStoreContextDidFetchRemoteValues` notification.
The corresponding value is an `AFHTTPRequestOperation` object representing the associated request. */
extern NSString * const AFIncrementalStoreRequestOperationKey;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextWillFetchRemoteValues` or `AFIncrementalStoreContextDidFetchRemoteValues` notification.
The corresponding value is an `NSPersistentStoreRequest` object representing the associated fetch or save request. */
extern NSString * const AFIncrementalStorePersistentStoreRequestKey;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextDidFetchRemoteValues` notification.
The corresponding value is an `NSArray` object containing the fetched objects, in the context in which they were requested.
*/
extern NSString * const AFIncrementalStoreFetchedObjectsKey;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextDidSaveRemoteValues` notification.
The corresponding value is an `NSArray` object containing the inserted objects, in the context in which they were requested.
*/
extern NSString * const AFIncrementalStoreInsertedObjectsKey;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextDidSaveRemoteValues` notification.
The corresponding value is an `NSArray` object containing the updated objects, in the context in which they were requested.
*/
extern NSString * const AFIncrementalStoreUpdatedObjectsKey;
/**
A key in the `userInfo` dictionary in a `AFIncrementalStoreContextWillSaveRemoteValues` or `AFIncrementalStoreContextDidFetchRemoteValues` notification.
The corresponding value is a NSArray containing the permament object ID's associated with the deleted objects from the originating managed object context. The object ID's are included in the NSNotification because unlike the NSManagedObjects themselves, the IDs are thread-safe.
*/
extern NSString * const AFIncrementalStoreDeletedObjectIDsKey;