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
NSManagedObjectContext
instances at runtime. OneNSMainQueueConcurrencyType
which will be used to display your model to the UI and oneNSPrivateQueueConcurrencyType
which 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.