From c8ca496639dfa73851b7b1a4e050a5aeea3a2c4a Mon Sep 17 00:00:00 2001 From: Isaac Kearse Date: Mon, 26 Jul 2010 19:28:28 +1200 Subject: [PATCH] Refactor deserialization to support format config Add a remoteSiteFormat property to CoreManager to enable setting the format in the app delegate in the same way as remoteSiteURL. This patch also lays the foundation for other deserializers by removing a hardcoded reference to JSON in CoreResource, although it falls back to JSON if no format is specified. --- CoreDeserializer.m | 57 ++++++++++++++++++++-------------------------- CoreManager.h | 2 ++ CoreManager.m | 6 ++++- CoreResource.h | 3 ++- CoreResource.m | 14 ++++++++---- 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/CoreDeserializer.m b/CoreDeserializer.m index 8f1d2aa..fa87166 100644 --- a/CoreDeserializer.m +++ b/CoreDeserializer.m @@ -29,38 +29,31 @@ - (id) initWithSource:(id)sourceObj andResourceClass:(Class)clazz { - (void) main { - // Use format to change deserialization class and convert serialized string into resources - Class newClass = [resourceClass performSelector:@selector(deserializerClassForFormat:) withObject:[self format]]; - if (newClass != nil) { - - // Get Core Manager from resource class if it hasn't been defined yet - if (coreManager == nil) - coreManager = [[resourceClass performSelector:@selector(coreManager)] retain]; - - // Create "scratchpad" object context; we will merge this context into the main context once deserialization is complete - managedObjectContext = [[coreManager newContext] retain]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(contextDidSave:) - name:NSManagedObjectContextDidSaveNotification - object:managedObjectContext]; - - resources = [[self resourcesFromString:[self sourceString]] retain]; - - // Attempt to save object context; if there's an error, it will be placed in the CoreResult (which is sent to the target) - [managedObjectContext save:&error]; - - [self performSelectorOnMainThread:@selector(notify) withObject:nil waitUntilDone:NO]; - - // Remove context save observer - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSManagedObjectContextDidSaveNotification object:managedObjectContext]; - - return; - } - - // Log error if level is high enough - if (error != nil && coreManager.logLevel > 3) - NSLog(@"CoreDeserializer error: %@", [error description]); + // Get Core Manager from resource class if it hasn't been defined yet + if (coreManager == nil) + coreManager = [[resourceClass performSelector:@selector(coreManager)] retain]; + + // Create "scratchpad" object context; we will merge this context into the main context once deserialization is complete + managedObjectContext = [[coreManager newContext] retain]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contextDidSave:) + name:NSManagedObjectContextDidSaveNotification + object:managedObjectContext]; + + resources = [[self resourcesFromString:[self sourceString]] retain]; + + // Attempt to save object context; if there's an error, it will be placed in the CoreResult (which is sent to the target) + [managedObjectContext save:&error]; + + [self performSelectorOnMainThread:@selector(notify) withObject:nil waitUntilDone:NO]; + + // Remove context save observer + [[NSNotificationCenter defaultCenter] removeObserver:self + name:NSManagedObjectContextDidSaveNotification object:managedObjectContext]; + + // Log error if level is high enough + if (error != nil && coreManager.logLevel > 3) + NSLog(@"CoreDeserializer error: %@", [error description]); } diff --git a/CoreManager.h b/CoreManager.h index f7637a0..cd31c7e 100644 --- a/CoreManager.h +++ b/CoreManager.h @@ -17,6 +17,7 @@ NSOperationQueue *deserialzationQueue; NSString *remoteSiteURL; + NSString *remoteSiteFormat; // Default setting for whether or not to get data from within the bundle (instead of performing remote HTTP requests) BOOL useBundleRequests; @@ -42,6 +43,7 @@ @property (nonatomic, retain) NSOperationQueue *deserialzationQueue; @property (nonatomic, retain) NSString *remoteSiteURL; +@property (nonatomic, retain) NSString *remoteSiteFormat; @property (nonatomic, assign) BOOL useBundleRequests; @property (nonatomic, assign) float bundleRequestDelay; diff --git a/CoreManager.m b/CoreManager.m index 89136c7..c575869 100644 --- a/CoreManager.m +++ b/CoreManager.m @@ -16,7 +16,7 @@ @implementation CoreManager @synthesize persistentStoreCoordinator, managedObjectContext, managedObjectModel; @synthesize requestQueue, deserialzationQueue; -@synthesize remoteSiteURL, useBundleRequests, bundleRequestDelay, defaultDateParser; +@synthesize remoteSiteURL, remoteSiteFormat, useBundleRequests, bundleRequestDelay, defaultDateParser; @synthesize entityDescriptions, modelProperties, modelRelationships, modelAttributes; @synthesize logLevel; @@ -54,6 +54,9 @@ - (id) initWithOptions:(NSDictionary*)options { logLevel = 1; + if (remoteSiteFormat == nil) + remoteSiteFormat = @"json"; + // ===== Core Data initialization ===== // // Create primary managed object model @@ -170,6 +173,7 @@ - (void)dealloc { [modelRelationships release]; [remoteSiteURL release]; + [remoteSiteFormat release]; [managedObjectContext release]; [managedObjectModel release]; diff --git a/CoreResource.h b/CoreResource.h index 36dd289..d0aee46 100644 --- a/CoreResource.h +++ b/CoreResource.h @@ -31,6 +31,7 @@ typedef enum _Action { + (BOOL) useBundleRequests; + (NSString*) remoteSiteURL; ++ (NSString*) remoteSiteFormat; + (NSString*) remoteCollectionName; + (NSString*) remoteURLForCollectionAction:(Action)action; + (NSString*) remoteURLForResource:(id)resourceId action:(Action)action; @@ -55,7 +56,7 @@ typedef enum _Action { + (NSDateFormatter*) dateParser; + (NSDateFormatter*) dateParserForField:(NSString*)field; -+ (Class) deserializerClassForFormat:(NSString*)format; ++ (Class) deserializerClass; //+ (id) resourceCollectionFromJSONCollection:(id)jsonCollection withParent:(id)parent; //+ (id) resourcePropertiesFromJSONElement:(id)jsonElement withParent:(id)parent; diff --git a/CoreResource.m b/CoreResource.m index 223daee..6be3d68 100644 --- a/CoreResource.m +++ b/CoreResource.m @@ -32,6 +32,10 @@ + (NSString*) remoteSiteURL { return [[self coreManager] remoteSiteURL]; } ++ (NSString*) remoteSiteFormat { + return [[self coreManager] remoteSiteFormat]; +} + + (NSString*) remoteCollectionName { return [[[NSStringFromClass(self) deCamelizeWith:@"_"] substringFromIndex:1] stringByAppendingString:@"s"]; } @@ -103,8 +107,8 @@ + (NSDateFormatter*) dateParserForField:(NSString*)field { return [self dateParser]; } -+ (Class) deserializerClassForFormat:(NSString*)format { - return NSClassFromString($S(@"Core%@Deserializer", [format uppercaseString])); ++ (Class) deserializerClass { + return NSClassFromString($S(@"Core%@Deserializer", [[self remoteSiteFormat] uppercaseString])); } /** @@ -603,7 +607,7 @@ + (void) findRemote:(id)resourceId { + (void) findRemote:(id)resourceId andNotify:(id)del withSelector:(SEL)selector { CoreRequest *request = [[[CoreRequest alloc] initWithURL: - [CoreUtils URLWithSite:[self remoteURLForResource:resourceId action:Read] andFormat:@"json" andParameters:nil]] autorelease]; + [CoreUtils URLWithSite:[self remoteURLForResource:resourceId action:Read] andFormat:[self remoteSiteFormat] andParameters:nil]] autorelease]; request.delegate = self; request.didFinishSelector = @selector(findRemoteDidFinish:); request.didFailSelector = @selector(findRemoteDidFail:); @@ -632,7 +636,7 @@ + (void) findAllRemote:(id)parameters { + (void) findAllRemote:(id)parameters andNotify:(id)del withSelector:(SEL)selector { CoreRequest *request = [[[CoreRequest alloc] initWithURL: - [CoreUtils URLWithSite:[self remoteURLForCollectionAction:Read] andFormat:@"json" andParameters:parameters]] autorelease]; + [CoreUtils URLWithSite:[self remoteURLForCollectionAction:Read] andFormat:[self remoteSiteFormat] andParameters:parameters]] autorelease]; request.delegate = self; request.didFinishSelector = @selector(findRemoteDidFinish:); request.didFailSelector = @selector(findRemoteDidFail:); @@ -653,7 +657,7 @@ + (void) findAllRemote:(id)parameters andNotify:(id)del withSelector:(SEL)select + (void) findRemoteDidFinish:(CoreRequest*)request { // Create and enqueue deserializer in non-blocking thread - CoreDeserializer* deserializer = [[CoreJSONDeserializer alloc] initWithSource:request andResourceClass:self]; + CoreDeserializer* deserializer = [[[self deserializerClass] alloc] initWithSource:request andResourceClass:self]; deserializer.target = request.coreDelegate; deserializer.action = request.coreSelector; [[[self coreManager] deserialzationQueue] addOperation:deserializer];