Skip to content

Instantly share code, notes, and snippets.

@chadpod
Created March 17, 2011 01:40
Show Gist options
  • Save chadpod/873705 to your computer and use it in GitHub Desktop.
Save chadpod/873705 to your computer and use it in GitHub Desktop.
Django Piston -> HTTPRiot -> Core Data parser/converter. Was using this approach prior to moving over to RestKit framework (http://restkit.org/).
//
// HRObject.m
//
// Created by Chad Podoski on 11/23/09.
// Copyright 2009 Shacked Software. All rights reserved.
//
#import "HRObject.h"
#import "AppDelegate_Shared.h"
@interface HRObject (Private)
+ (void)populateObject:(id)object withDictionary:(NSDictionary *)dict;
+ (id)managedObjectForEntity:(NSString *)entity uuid:(NSString *)uuid;
@end
@implementation HRObject
+ (void)initialize {
[self setDelegate:self];
[self setBaseURL:[NSURL URLWithString:SSBaseApiUrl]];
[self setFormat:HRDataFormatJSON];
//NSDictionary *params = [NSDictionary dictionaryWithObject:@"1234567" forKey:@"api_key"];
//[self setDefaultParams:params];
}
/**
* Called when the resource was succeffully fetched and encoded
*
* @param connection The connection object for the current request
* @param resource The converted objc representation of the response data returned by the server.
* @param object Any custom object you passed in while making the request.
*/
+ (void)restConnection:(NSURLConnection *)connection didReturnResource:(id)resource object:(id)object {
/* Converts from the HTTPRiot model class to Core Data Model class and CRUD in managed object context */
NSMutableSet *responseSet = [self convertToCoreData:resource];
if (!IsEmpty(object) && [object respondsToSelector:@selector(httpRiotResponseReceived:)]) {
[object performSelector:@selector(httpRiotResponseReceived:) withObject:responseSet];
}
}
/**
* Called when the connection receieves any type of response
*
* @param connection The connection object for the current request
* @param response The response object returned by the server.
* @param object Any custom object you passed in while making the request.
*/
+ (void)restConnection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response object:(id)object {
NSLog(@"RESPONSE STATUS WAS:%i", [response statusCode]);
}
/**
* Called when the connection fails in situations where the server is not available, etc.
*
* @param connection The connection object for the current request
* @param error The error returned by the connection.
* @param object Any custom object you passed in while making the request.
*/
+ (void)restConnection:(NSURLConnection *)connection didFailWithError:(NSError *)error object:(id)object {
AlertWithMessage([error localizedDescription]);
}
/**
* Called when the connection receieves a statusCode that isn't a success code.
*
* @param connection The connection object for the current request
* @param error The error returned by the connection.
* @param response The response object returned by the server.
* @param object Any custom object you passed in while making the request.
*/
+ (void)restConnection:(NSURLConnection *)connection didReceiveError:(NSError *)error response:(NSHTTPURLResponse *)response object:(id)object {
AlertWithMessage([error localizedDescription]);
}
/**
* Called when the HRFormatter recieved an error parsing the response data.
*
* @param connection The connection object for the current request
* @param error The parser error returned by the formatter.
* @param body A string representation of the response body returned by the server.
* @param object Any custom object you passed in while making the request.
*/
+ (void)restConnection:(NSURLConnection *)connection didReceiveParseError:(NSError *)error responseBody:(NSString *)body object:(id)object {
AlertWithMessage([error localizedDescription]);
}
#pragma mark - Core Data Methods
+ (NSMutableSet *)convertToCoreData:(id)resource {
NSMutableSet *result;
/* Determine if we are dealing with a single object or an array of objects */
if ([resource isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = (NSDictionary *)resource;
NSString *entity = [dict valueForKey:SSEntityKey];
NSString *uuid = [dict valueForKey:SSUuidKey];
/* Make sure object an entity name and an uuid */
if (!IsEmpty(entity) && !IsEmpty(uuid)) {
result = [NSMutableSet setWithCapacity:1];
/* Class name needs to be prefixed with class prefix for this project */
id object = [self managedObjectForEntity:entity uuid:uuid];
// NSLog(@"******************************");
// NSLog(@"BEFORE %@", object);
[self populateObject:object withDictionary:resource];
// NSLog(@"------------------------------");
// NSLog(@"AFTER %@", object);
[result addObject:object];
}
}else if ([resource isKindOfClass:[NSArray class]]) {
result = [NSMutableSet setWithCapacity:[(NSArray *)resource count]];
for (id object in resource) {
[result unionSet:[self convertToCoreData:object]];
}
}
return result;
}
+ (void)populateObject:(id)object withDictionary:(NSDictionary *)dict {
NSArray *keys = [dict allKeys];
for (NSString *key in keys) {
id value = [dict valueForKey:key];
key = [key capitalizedString];
key = [key stringByReplacingOccurrencesOfString:@"_" withString:@""];
/* An NSArray value indicates that this is a relation */
if ([value isKindOfClass:[NSArray class]]) {
/* Recursive build the relation */
NSMutableSet *relationSet = [self convertToCoreData:value];
/* Add relation to object */
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"add%@:", key]);
if ([object respondsToSelector:selector]) {
[object performSelector:selector withObject:relationSet];
}
}
/* A NSDictionary indicate a 1-to-1 relationship from Django Piston */
else if ([value isKindOfClass:[NSDictionary class]]) {
NSMutableSet *relationSet = [self convertToCoreData:value];
if (!IsEmpty(relationSet) && [relationSet count] == 1) {
/* Add object to model */
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", key]);
if ([object respondsToSelector:selector]) {
[object performSelector:selector withObject:[relationSet anyObject]];
}
}
}
/* It is a simple attribute */
else {
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:", key]);
if ([object respondsToSelector:setter]) {
if (!IsEmpty(value) && ![value isEqual:[NSNull null]]) {
if ([value isKindOfClass:[NSString class]]) {
if (![value isEqualToString:@"<null>"]) {
/* Just lowercase the first character */
key = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] lowercaseString]];
SEL getter = NSSelectorFromString(key);
if ([object respondsToSelector:getter]) {
NSManagedObject *mObject = (NSManagedObject*)object;
NSPropertyDescription *propDesc = [[[[mObject class] entityDescription]
propertiesByName] objectForKey:key];
if ([propDesc isMemberOfClass:[NSAttributeDescription class]]) {
NSAttributeDescription *attribDesc = (NSAttributeDescription*)propDesc;
if ([attribDesc attributeType] == NSDateAttributeType) {
NSDate *date = [NSDate dateFromString:value];
if (!IsEmpty(date)) {
[object performSelector:setter withObject:date];
}
}
else if ([attribDesc attributeType] == NSDecimalAttributeType) {
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:value];
if (!IsEmpty(number)) {
[object performSelector:setter withObject:number];
}
}
else {
[object performSelector:setter withObject:value];
}
}
}
}
}
else {
[object performSelector:setter withObject:value];
}
}
}
}
}
}
+ (id)managedObjectForEntity:(NSString *)entity uuid:(NSString *)uuid {
id object;
NSManagedObjectContext *moc = [(AppDelegate_Shared*)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:entity inManagedObjectContext:moc]];
[request setPredicate:[NSPredicate predicateWithFormat:@"uuid = %@", uuid]];
NSError *error = nil;
NSArray *results = [moc executeFetchRequest:request error:&error];
if (error) {
NSLog(@"%@", error);
}
else if (!IsEmpty(results)) {
object = [results objectAtIndex:0];
}
else {
object = [NSEntityDescription insertNewObjectForEntityForName:entity inManagedObjectContext:moc];;
}
return object;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment