Skip to content

Latest commit

 

History

History
213 lines (146 loc) · 7.6 KB

README.md

File metadata and controls

213 lines (146 loc) · 7.6 KB

SLRESTfulCoreData Build Status Version Badge License Badge

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.

Getting started

  • Add
pod 'SLRESTfulCoreData'

to your Podfile.

  • Instead of subclassing AFHTTPClient, subclass AFRESTfulCoreDataBackgroundQueue
@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. One NSMainQueueConcurrencyType which will be used to display your model to the UI and one NSPrivateQueueConcurrencyType 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 subclass SLCoreDataStack:
@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;
    }];
    
    ...
}

Attribute mappings

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.

Fetching objects from your API

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

CRUD for your model

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

URL substitution

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.

CRUD for relationships

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.