diff --git a/ESObjectMap/ESBaseModelObject.h b/ESObjectMap/ESBaseModelObject.h index 9ac3356..c3d8776 100644 --- a/ESObjectMap/ESBaseModelObject.h +++ b/ESObjectMap/ESBaseModelObject.h @@ -18,15 +18,12 @@ // #import -#import "NSObject+PropertyDictionary.h" #import "ESObjectMap.h" +#import "ESObjectProtocol.h" -@interface ESBaseModelObject : NSObject +@interface ESBaseModelObject : NSObject -+ (ESObjectMap *)objectMap; + (id)newWithDictionary:(NSDictionary *)dictionary; - (id)initWithDictionary:(NSDictionary *)dictionary; -- (void)configureWithDictionary:(NSDictionary *)dictionary; -- (NSDictionary *)dictionaryRepresentation; @end diff --git a/ESObjectMap/ESBaseModelObject.m b/ESObjectMap/ESBaseModelObject.m index 165f2c6..4a568b4 100644 --- a/ESObjectMap/ESBaseModelObject.m +++ b/ESObjectMap/ESBaseModelObject.m @@ -45,174 +45,12 @@ - (id)initWithDictionary:(NSDictionary *)dictionary - (void)configureWithDictionary:(NSDictionary *)dictionary { - NSDictionary *propertyDictionary = [[self class] propertyDictionary]; - ESObjectMap *objectMap = [[self class] objectMap]; - for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues]) - { - @autoreleasepool { - NSString *inputKey; - NSString *outputKey; - id dictionaryValue; - id propertyValue; - - outputKey = attributes.name; - if (outputKey == nil) - continue; - // Get the property map, if it exists - ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey]; - if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey - inputKey = outputKey; - else // If there is a property map, get the input key - inputKey = propertyMap.inputKey; - // Grab our value from the input dictionary - dictionaryValue = [dictionary objectForKey:inputKey]; - if (dictionaryValue == nil) - continue; - // At this point we have a value to work with, so let's make sure we can actually set it - if (attributes.readOnly) - [NSException raise:@"Readonly Exception" format:@"Attempted to set a readonly property: %@", attributes]; - switch (attributes.storageType) { - case IDType: - // If there's a transform block, execute it - if (propertyMap.transformBlock) - propertyValue = propertyMap.transformBlock(dictionaryValue); - else - propertyValue = dictionaryValue; - if (propertyValue == nil) - continue; - [self setValue:propertyValue forKey:outputKey]; - break; - case ObjectType: - // If there's a transform block, execute it - if (propertyMap.transformBlock) - propertyValue = propertyMap.transformBlock(dictionaryValue); - else - propertyValue = dictionaryValue; - if (propertyValue == nil) - continue; - Class class = NSClassFromString(attributes.classString); - if (class && ![propertyValue isKindOfClass:class]) - [NSException raise:@"Class Mismatch" format:@"Object: %@ is not kind of class: %@", propertyValue, NSStringFromClass(class)]; - [self setValue:propertyValue forKey:outputKey]; - break; - case IntType: - { - int intPropertyValue = 0; - // If there's a transform block, execute it - if (((ESIntPropertyMap *)propertyMap).intTransformBlock) - intPropertyValue = ((ESIntPropertyMap *)propertyMap).intTransformBlock(dictionaryValue); - else - intPropertyValue = [dictionaryValue intValue]; - SetPrimitivePropertyValue(self, attributes.setter, &intPropertyValue); - break; - } - case DoubleType: - { - double doublePropertyValue = 0.0; - // If there's a transform block, execute it - if (((ESDoublePropertyMap *)propertyMap).doubleTransformBlock) - doublePropertyValue = ((ESDoublePropertyMap *)propertyMap).doubleTransformBlock(dictionaryValue); - else - doublePropertyValue = [dictionaryValue doubleValue]; - SetPrimitivePropertyValue(self, attributes.setter, &doublePropertyValue); - break; - } - case FloatType: - { - float floatPropertyValue = 0.0f; - // If there's a transform block, execute it - if (((ESFloatPropertyMap *)propertyMap).floatTransformBlock) - floatPropertyValue = ((ESFloatPropertyMap *)propertyMap).floatTransformBlock(dictionaryValue); - else - floatPropertyValue = [dictionaryValue floatValue]; - SetPrimitivePropertyValue(self, attributes.setter, &floatPropertyValue); - break; - } - case BoolType: - { - BOOL boolPropertyValue = NO; - // If there's a transform block, execute it - if (((ESBOOLPropertyMap *)propertyMap).boolTransformBlock) - boolPropertyValue = ((ESBOOLPropertyMap *)propertyMap).boolTransformBlock(dictionaryValue); - else - boolPropertyValue = [dictionaryValue boolValue]; - SetPrimitivePropertyValue(self, attributes.setter, &boolPropertyValue); - break; - } - default: - break; - } - } - } + ConfigureObjectWithDictionary(self, dictionary); } - (NSDictionary *)dictionaryRepresentation { - NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary new]; - NSDictionary *propertyDictionary = [[self class] propertyDictionary]; - ESObjectMap *objectMap = [[self class] objectMap]; - for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues]) - { - @autoreleasepool { - NSString *inputKey; - NSString *outputKey; - id dictionaryValue; - id propertyValue; - - outputKey = attributes.name; - if (outputKey == nil) - continue; - // Get the property map, if it exists - ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey]; - if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey - inputKey = outputKey; - else // If there is a property map, get the input key - inputKey = propertyMap.inputKey; - switch (attributes.storageType) { - case IDType: - case ObjectType: - propertyValue = [self valueForKey:outputKey]; - if (propertyMap.inverseTransformBlock) - dictionaryValue = propertyMap.inverseTransformBlock(propertyValue); - else - dictionaryValue = propertyValue; - break; - case IntType: - { - int result; - GetPrimitivePropertyValue(self, attributes.getter, &result); - dictionaryValue = [NSNumber numberWithInt:result]; - break; - } - case DoubleType: - { - double result; - GetPrimitivePropertyValue(self, attributes.getter, &result); - dictionaryValue = [NSNumber numberWithDouble:result]; - break; - } - case FloatType: - { - float result; - GetPrimitivePropertyValue(self, attributes.getter, &result); - dictionaryValue = [NSNumber numberWithFloat:result]; - break; - } - case BoolType: - { - BOOL result; - GetPrimitivePropertyValue(self, attributes.getter, &result); - dictionaryValue = [NSNumber numberWithBool:result]; - break; - } - default: - break; - } - if (dictionaryValue) - [dictionaryRepresentation setObject:dictionaryValue forKey:inputKey]; - } - } - return dictionaryRepresentation; + return GetDictionaryRepresentation(self); } @end diff --git a/ESObjectMap/ESObjectMapFunctions.h b/ESObjectMap/ESObjectMapFunctions.h index 5a99cb3..2edbcb7 100644 --- a/ESObjectMap/ESObjectMapFunctions.h +++ b/ESObjectMap/ESObjectMapFunctions.h @@ -19,7 +19,10 @@ #import #import "ESObjectMap.h" +#import "ESObjectProtocol.h" +void ConfigureObjectWithDictionary(id object, NSDictionary *dictionary); +NSDictionary * GetDictionaryRepresentation(id object); ESObjectMap * GetObjectMapForClass(Class objectClass); void GetPrimitivePropertyValue(id object, SEL getter, void * value); void SetPrimitivePropertyValue(id object, SEL setter, void * value); diff --git a/ESObjectMap/ESObjectMapFunctions.m b/ESObjectMap/ESObjectMapFunctions.m index b9a6183..2a4ebec 100644 --- a/ESObjectMap/ESObjectMapFunctions.m +++ b/ESObjectMap/ESObjectMapFunctions.m @@ -20,6 +20,179 @@ #import "ESObjectMapFunctions.h" #import "ESMutableDictionary.h" #import +#import "NSObject+PropertyDictionary.h" + +void ConfigureObjectWithDictionary(id object, NSDictionary *dictionary) +{ + NSDictionary *propertyDictionary = [[object class] propertyDictionary]; + ESObjectMap *objectMap = [[object class] objectMap]; + for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues]) + { + @autoreleasepool { + NSString *inputKey; + NSString *outputKey; + id dictionaryValue; + id propertyValue; + + outputKey = attributes.name; + if (outputKey == nil) + continue; + // Get the property map, if it exists + ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey]; + if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey + inputKey = outputKey; + else // If there is a property map, get the input key + inputKey = propertyMap.inputKey; + // Grab our value from the input dictionary + dictionaryValue = [dictionary objectForKey:inputKey]; + if (dictionaryValue == nil) + continue; + // At this point we have a value to work with, so let's make sure we can actually set it + if (attributes.readOnly) + [NSException raise:@"Readonly Exception" format:@"Attempted to set a readonly property: %@", attributes]; + switch (attributes.storageType) { + case IDType: + // If there's a transform block, execute it + if (propertyMap.transformBlock) + propertyValue = propertyMap.transformBlock(dictionaryValue); + else + propertyValue = dictionaryValue; + if (propertyValue == nil) + continue; + [object setValue:propertyValue forKey:outputKey]; + break; + case ObjectType: + // If there's a transform block, execute it + if (propertyMap.transformBlock) + propertyValue = propertyMap.transformBlock(dictionaryValue); + else + propertyValue = dictionaryValue; + if (propertyValue == nil) + continue; + Class class = NSClassFromString(attributes.classString); + if (![propertyValue isKindOfClass:class]) + [NSException raise:@"Class Mismatch" format:@"Object: %@ is not kind of class: %@", propertyValue, NSStringFromClass(class)]; + [object setValue:propertyValue forKey:outputKey]; + break; + case IntType: + { + int intPropertyValue = 0; + // If there's a transform block, execute it + if (((ESIntPropertyMap *)propertyMap).intTransformBlock) + intPropertyValue = ((ESIntPropertyMap *)propertyMap).intTransformBlock(dictionaryValue); + else + intPropertyValue = [dictionaryValue intValue]; + SetPrimitivePropertyValue(object, attributes.setter, &intPropertyValue); + break; + } + case DoubleType: + { + double doublePropertyValue = 0.0; + // If there's a transform block, execute it + if (((ESDoublePropertyMap *)propertyMap).doubleTransformBlock) + doublePropertyValue = ((ESDoublePropertyMap *)propertyMap).doubleTransformBlock(dictionaryValue); + else + doublePropertyValue = [dictionaryValue doubleValue]; + SetPrimitivePropertyValue(object, attributes.setter, &doublePropertyValue); + break; + } + case FloatType: + { + float floatPropertyValue = 0.0f; + // If there's a transform block, execute it + if (((ESFloatPropertyMap *)propertyMap).floatTransformBlock) + floatPropertyValue = ((ESFloatPropertyMap *)propertyMap).floatTransformBlock(dictionaryValue); + else + floatPropertyValue = [dictionaryValue floatValue]; + SetPrimitivePropertyValue(object, attributes.setter, &floatPropertyValue); + break; + } + case BoolType: + { + BOOL boolPropertyValue = NO; + // If there's a transform block, execute it + if (((ESBOOLPropertyMap *)propertyMap).boolTransformBlock) + boolPropertyValue = ((ESBOOLPropertyMap *)propertyMap).boolTransformBlock(dictionaryValue); + else + boolPropertyValue = [dictionaryValue boolValue]; + SetPrimitivePropertyValue(object, attributes.setter, &boolPropertyValue); + break; + } + default: + break; + } + } + } +} + +NSDictionary * GetDictionaryRepresentation(id object) +{ + NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary new]; + NSDictionary *propertyDictionary = [[object class] propertyDictionary]; + ESObjectMap *objectMap = [[object class] objectMap]; + for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues]) + { + @autoreleasepool { + NSString *inputKey; + NSString *outputKey; + id dictionaryValue; + id propertyValue; + + outputKey = attributes.name; + if (outputKey == nil) + continue; + // Get the property map, if it exists + ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey]; + if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey + inputKey = outputKey; + else // If there is a property map, get the input key + inputKey = propertyMap.inputKey; + switch (attributes.storageType) { + case IDType: + case ObjectType: + propertyValue = [object valueForKey:outputKey]; + if (propertyMap.inverseTransformBlock) + dictionaryValue = propertyMap.inverseTransformBlock(propertyValue); + else + dictionaryValue = propertyValue; + break; + case IntType: + { + int result; + GetPrimitivePropertyValue(object, attributes.getter, &result); + dictionaryValue = [NSNumber numberWithInt:result]; + break; + } + case DoubleType: + { + double result; + GetPrimitivePropertyValue(object, attributes.getter, &result); + dictionaryValue = [NSNumber numberWithDouble:result]; + break; + } + case FloatType: + { + float result; + GetPrimitivePropertyValue(object, attributes.getter, &result); + dictionaryValue = [NSNumber numberWithFloat:result]; + break; + } + case BoolType: + { + BOOL result; + GetPrimitivePropertyValue(object, attributes.getter, &result); + dictionaryValue = [NSNumber numberWithBool:result]; + break; + } + default: + break; + } + if (dictionaryValue) + [dictionaryRepresentation setObject:dictionaryValue forKey:inputKey]; + } + } + return dictionaryRepresentation; +} static ESMutableDictionary *_objectMapCache; diff --git a/ESObjectMap/ESObjectProtocol.h b/ESObjectMap/ESObjectProtocol.h new file mode 100644 index 0000000..53190f0 --- /dev/null +++ b/ESObjectMap/ESObjectProtocol.h @@ -0,0 +1,32 @@ +// +// ESObjectProtocol.h +// +// Created by Doug Russell +// Copyright (c) 2011 Doug Russell. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "NSObject+PropertyDictionary.h" +#import "ESObjectMap.h" + +@protocol ESObject + ++ (ESObjectMap *)objectMap; +- (void)configureWithDictionary:(NSDictionary *)dictionary; +- (NSDictionary *)dictionaryRepresentation; +- (id)valueForKey:(NSString *)key; +- (void)setValue:(id)value forKey:(NSString *)key; + +@end diff --git a/ESObjectMap/NSManagedObject+ESObject.h b/ESObjectMap/NSManagedObject+ESObject.h new file mode 100644 index 0000000..752f87c --- /dev/null +++ b/ESObjectMap/NSManagedObject+ESObject.h @@ -0,0 +1,14 @@ +// +// NSManagedObject+ESObject.h +// ESObjectMap +// +// Created by Doug Russell on 9/17/11. +// Copyright (c) 2011 Doug Russell. All rights reserved. +// + +#import +#import "ESObjectProtocol.h" + +@interface NSManagedObject (ESObject) + +@end diff --git a/ESObjectMap/NSManagedObject+ESObject.m b/ESObjectMap/NSManagedObject+ESObject.m new file mode 100644 index 0000000..a28866d --- /dev/null +++ b/ESObjectMap/NSManagedObject+ESObject.m @@ -0,0 +1,29 @@ +// +// NSManagedObject+ESObject.m +// ESObjectMap +// +// Created by Doug Russell on 9/17/11. +// Copyright (c) 2011 Doug Russell. All rights reserved. +// + +#import "NSManagedObject+ESObject.h" +#import "ESObjectMapFunctions.h" + +@implementation NSManagedObject (ESObject) + ++ (ESObjectMap *)objectMap +{ + return GetObjectMapForClass([self class]); +} + +- (void)configureWithDictionary:(NSDictionary *)dictionary +{ + ConfigureObjectWithDictionary(self, dictionary); +} + +- (NSDictionary *)dictionaryRepresentation +{ + return GetDictionaryRepresentation(self); +} + +@end