Objc naming conventions, autogenerated accessors at runtime, URL substitutions and intelligent attribute mapping
SLRESTfulCoreData builds on top of AFNetworking and SLCoreDataStack and lets you map your JSON REST API to your CoreData model in minutes. Checkout this blog post or this sample project for getting started.
- Add
pod 'SLRESTfulCoreData'
to your Podfile.
- Instead of subclassing
AFHTTPClient, subclassAFRESTfulCoreDataBackgroundQueue
@interface GHBackgroundQueue : AFRESTfulCoreDataBackgroundQueue
@end
@interface GHBackgroundQueue (Singleton)
+ (GHBackgroundQueue *)sharedInstance;
@end
and register your background queue as the default background queue in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSManagedObject setDefaultBackgroundQueue:[GHBackgroundQueue sharedInstance]];
...
}
- You need to provide two
NSManagedObjectContextinstances at runtime. OneNSMainQueueConcurrencyTypewhich will be used to display your model to the UI and oneNSPrivateQueueConcurrencyTypewhich will be used to updated for CoreData model with data coming from the API. Implementing a new CoreData Stack can be challenging. Therefore, SLRESTfulCoreData ships by default with the SLCoreDataStack dependency. You need to subclassSLCoreDataStack:
@interface GHDataStoreManager : SLCoreDataStack
@end
@implementation GHDataStoreManager
- (NSString *)managedObjectModelName
{
return @"GithubAPI"; // return the name of your CoreData model here.
}
@end
and register both contexts
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSManagedObject registerDefaultBackgroundThreadManagedObjectContextWithAction:^NSManagedObjectContext *{
return [GHDataStoreManager sharedInstance].backgroundThreadManagedObjectContext;
}];
[NSManagedObject registerDefaultMainThreadManagedObjectContextWithAction:^NSManagedObjectContext *{
return [GHDataStoreManager sharedInstance].mainThreadManagedObjectContext;
}];
...
}
SLRESTfulCoreData maps underscored API attributes to camelized objc attributes by default. That means by default some_json_value will be mapped to someJsonValue and user_id to userId. Custom attribute mappings can be registered in your NSManagedObject subclass's initializer:
+ (void)initialize
{
// register multiple attribute mappings at once
[self registerAttributeMapping:@{
@"someJSONValue": @"some_json_value"
}];
// register one attribute mapping
[self registerAttributeName:@"someJSONValue" forJSONObjectKeyPath:@"some_json_value"];
}
SLRESTfulCoreData supports naming conventions in case you don't want to repeat yourself in attribute mappings all the time. Therefore you can register global default naming conventions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
[SLAttributeMapping registerDefaultObjcNamingConvention:@"identifier" forJSONNamingConvention:@"id"];
[SLAttributeMapping registerDefaultObjcNamingConvention:@"URL" forJSONNamingConvention:@"url"];
}
From now on, an API attribute id will always be mapped to identifier and every API attribute containing an id key will be mapped to an identifier in objc. For example user_id will automatically be mapped to userIdentifier and some_url_value to someURLValue.
SLRESTfulCoreData extends NSManagedObject for fetching objects from your API by
@interface NSManagedObject (SLRESTfulCoreDataQueryInterface)
+ (void)fetchObjectFromURL:(NSURL *)URL
completionHandler:(void(^)(id fetchedObject, NSError *error))completionHandler;
+ (void)fetchObjectsFromURL:(NSURL *)URL
completionHandler:(void(^)(NSArray *fetchedObjects, NSError *error))completionHandler;
- (void)fetchObjectsForRelationship:(NSString *)relationship
fromURL:(NSURL *)URL
completionHandler:(void (^)(NSArray *fetchedObjects, NSError *error))completionHandler;
- (void)postToURL:(NSURL *)URL completionHandler:(void (^)(id JSONObject, NSError *error))completionHandler;
- (void)putToURL:(NSURL *)URL completionHandler:(void (^)(id JSONObject, NSError *error))completionHandler;
- (void)deleteToURL:(NSURL *)URL completionHandler:(void (^)(NSError *error))completionHandler;
@end
You can use them like
@interface GHUser : NSManagedObject
+ (void)userWithName:(NSString *)name completionHandler:(void(^)(GHUser *user, NSError *error))completionHandler;
@end
@implementation GHUser
+ (void)userWithName:(NSString *)name completionHandler:(void(^)(GHUser *user, NSError *error))completionHandler
{
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"/users/%@", name]];
[self fetchObjectFromURL:URL completionHandler:completionHandler];
}
@end
SLRESTfulCoreData ships with CRUD support for your model. Simply register a CRUD base URL
+ (void)initialize
{
[self registerCRUDBaseURL:[NSURL URLWithString:@"/repos/:repository.full_name/issues"]];
}
and use the following methods
@interface NSManagedObject (SLRESTfulCoreDataQueryInterface)
// GET /repos/:repository.full_name/issues/:number
- (void)updateWithCompletionHandler:(void(^)(id managedObject, NSError *error))completionHandler;
// POST /repos/:repository.full_name/issues
- (void)createWithCompletionHandler:(void(^)(id managedObject, NSError *error))completionHandler;
// POT /repos/:repository.full_name/issues/:number
- (void)saveWithCompletionHandler:(void(^)(id managedObject, NSError *error))completionHandler;
// DELETE /repos/:repository.full_name/issues/:number
- (void)deleteWithCompletionHandler:(void(^)(NSError *error))completionHandler;
@end
The above used key path repository.full_name will be transformed to the objc key path repository.fullName based on your registered attribute mappings and naming conventions and will be evaluated with the correct NSManagedObject instance.
SLRESTfulCoreData lets you register CRUD base URLs for relationships
@implementation GHUser
+ (void)initialize
{
[self registerCRUDBaseURL:[NSURL URLWithString:@"/repos/:repository.full_name/issues"] forRelationship:@"issues"];
}
@end
which will implement and provide
@interface GHRepository (CoreDataGeneratedAccessors)
// GET /repos/:self.full_name/issues
- (void)issuesWithCompletionHandler:(void(^)(NSArray *issues, NSError *error))completionHandler;
// POST /repos/:repository.full_name/issues
- (void)addIssuesObject:(GHIssue *)issue withCompletionHandler:(void(^)(GHIssue *issue, NSError *error))completionHandler;
// DELETE /repos/:repository.full_name/issues/:number
- (void)deleteIssuesObject:(GHIssue *)issue withCompletionHandler:(void(^)(NSError *error))completionHandler;
@end
at runtime for you.


