diff --git a/NSObject+Motis.h b/NSObject+Motis.h index bc54497..3256234 100644 --- a/NSObject+Motis.h +++ b/NSObject+Motis.h @@ -87,7 +87,6 @@ @end - /* * MOTIS AUTOMATIC VALIDATION * diff --git a/NSObject+Motis.m b/NSObject+Motis.m index aabec5c..d9f6a86 100644 --- a/NSObject+Motis.m +++ b/NSObject+Motis.m @@ -70,6 +70,11 @@ - (id)initWithKeyPath:(NSString*)keyPath @end +#pragma mark - +// ------------------------------------------------------------------------------------------------------------------------------------------------------------------ // +// ------------------------------------------------------------------------------------------------------------------------------------------------------------------ // +// ------------------------------------------------------------------------------------------------------------------------------------------------------------------ // + @interface NSObject (Motis_Private) /** ---------------------------------------------- ** @@ -114,12 +119,12 @@ - (NSString*)mts_typeAttributeForKey:(NSString*)key; - (BOOL)mts_isClassTypeTypeAttribute:(NSString*)typeAttribute; /** - * Returns the class object for the given attribute type or nil if cannot be created. + * Retrieve the class name and the array of protocols that the property implements. + * @param className The returning class name. + * @param protocols The returning array of protocols. * @param typeAttribute The value returned by `-mts_typeAttributeForKey:`. - * @return The related class object. */ -- (Class)mts_classForTypeAttribute:(NSString*)typeAttribute; - +- (void)mts_getClassName:(out NSString *__autoreleasing*)className protocols:(out NSArray *__autoreleasing*)protocols fromTypeAttribute:(NSString*)typeAttribute; /** ---------------------------------------------- ** * @name Automatic Validation @@ -567,15 +572,28 @@ - (BOOL)mts_isClassTypeTypeAttribute:(NSString*)typeAttribute return [typeAttribute hasPrefix:@"T@"] && ([typeAttribute length] > 1); } -- (Class)mts_classForTypeAttribute:(NSString*)typeAttribute +- (void)mts_getClassName:(out NSString *__autoreleasing*)className protocols:(out NSArray *__autoreleasing*)protocols fromTypeAttribute:(NSString*)typeAttribute { if ([self mts_isClassTypeTypeAttribute:typeAttribute]) { - NSString *typeClassName = [typeAttribute substringWithRange:NSMakeRange(3, [typeAttribute length]-4)]; - return NSClassFromString(typeClassName); + typeAttribute = [typeAttribute substringWithRange:NSMakeRange(3, typeAttribute.length-4)]; + + NSString *protocolNames = nil; + + NSScanner *scanner = [NSScanner scannerWithString:typeAttribute]; + [scanner scanUpToString:@"<" intoString:className]; + [scanner scanUpToString:@">" intoString:&protocolNames]; + + if (*className == nil) + *className = @""; + + if (protocolNames.length > 0) + { + protocolNames = [protocolNames substringFromIndex:1]; + protocolNames = [protocolNames stringByReplacingOccurrencesOfString:@" " withString:@""]; + *protocols = [protocolNames componentsSeparatedByString:@","]; + } } - - return nil; } - (BOOL)mts_validateAutomaticallyValue:(inout __autoreleasing id *)ioValue forKey:(NSString*)key @@ -593,15 +611,35 @@ - (BOOL)mts_validateAutomaticallyValue:(inout __autoreleasing id *)ioValue forKe if ([self mts_isClassTypeTypeAttribute:typeAttribute]) { - if (strcmp(rawPropertyType, @encode(id)) == 0) - return YES; + NSString *className = nil; + NSArray *protocols = nil; - Class typeClass = [self mts_classForTypeAttribute:typeAttribute]; + [self mts_getClassName:&className protocols:&protocols fromTypeAttribute:typeAttribute]; - if (typeClass != nil) + if (className.length == 0) { - MJLog(@"%@ --> %@", key, NSStringFromClass(typeClass)); - return [self mts_validateAutomaticallyValue:ioValue toClass:typeClass forKey:key]; + // It's an "id". + + // Actually, we should make a compare like this: + // if (strcmp(rawPropertyType, @encode(id)) == 0) + // return YES; + // + // However, becuase of the "if" statements, we know that our typeAttribute begins with a "@" and + // if "className.length" == 0 means that the "rawPropertyType" to be compared is exactly an @encode(id). + // + // Therefore, we return directly YES. + + return YES; + } + else + { + Class typeClass = NSClassFromString(className); + + if (typeClass) + { + MJLog(@"%@ --> %@", key, NSStringFromClass(typeClass)); + return [self mts_validateAutomaticallyValue:ioValue toClass:typeClass forKey:key]; + } } return NO; diff --git a/SampleProject/Motis Tests/MJTestObject.h b/SampleProject/Motis Tests/MJTestObject.h index 4f65cf8..79d38ed 100644 --- a/SampleProject/Motis Tests/MJTestObject.h +++ b/SampleProject/Motis Tests/MJTestObject.h @@ -22,6 +22,9 @@ @property (nonatomic, strong) NSNumber *numberField; @property (nonatomic, strong) NSURL *urlField; +@property (nonatomic, strong) id idField; +@property (nonatomic, strong) id idProtocolField; + // This property is not included in the mapping @property (nonatomic, strong) NSString *privateStringField; diff --git a/SampleProject/Motis Tests/MJTestObject.m b/SampleProject/Motis Tests/MJTestObject.m index 2d2f312..3830ff0 100644 --- a/SampleProject/Motis Tests/MJTestObject.m +++ b/SampleProject/Motis Tests/MJTestObject.m @@ -26,6 +26,9 @@ + (NSDictionary*)mts_mapping @"number": mts_key(numberField), @"url": mts_key(urlField), + @"id": mts_key(idField), + @"id_protocol": mts_key(idProtocolField), + @"string1.string2.string3" : mts_key(stringField), @"url1.url2.url3" : mts_key(urlField), }; diff --git a/SampleProject/Motis Tests/Motis_Tests.m b/SampleProject/Motis Tests/Motis_Tests.m index 3b8f739..5246a95 100644 --- a/SampleProject/Motis Tests/Motis_Tests.m +++ b/SampleProject/Motis Tests/Motis_Tests.m @@ -175,6 +175,30 @@ - (void)testNumberToString } } +#pragma mark to id + +- (void)testNumberToId +{ + for (NSNumber *number in [self mts_arrayWithNumbers]) + { + _object.idField = nil; + [_object mts_setValue:number forKey:@"id"]; + if (![_object.idField isEqualToNumber:number]) + XCTFail(@"Failed to map number value %@", number.description); + } +} + +- (void)testNumberToIdProtocol +{ + for (NSNumber *number in [self mts_arrayWithNumbers]) + { + _object.idField = nil; + [_object mts_setValue:number forKey:@"id_protocol"]; + if (![(NSNumber*)_object.idProtocolField isEqualToNumber:number]) + XCTFail(@"Failed to map number value %@", number.description); + } +} + #pragma mark - FROM STRING // ------------------------------------------------------------------------------------------------------------------------ // @@ -274,6 +298,26 @@ - (void)testStringToUrl XCTFail(@"Failed to map string value %@", string); } +#pragma mark to id + +- (void)testStringToId +{ + NSString *string = @"Hello World"; + [_object mts_setValue:string forKey:@"id"]; + + if (![_object.idField isEqualToString:string]) + XCTFail(@"Failed to map string value %@", string); +} + +- (void)testStringToIdProtocol +{ + NSString *string = @"Hello World"; + [_object mts_setValue:string forKey:@"id_protocol"]; + + if (![(NSString*)_object.idProtocolField isEqualToString:string]) + XCTFail(@"Failed to map string value %@", string); +} + #pragma mark - FROM DICTIONARY // ------------------------------------------------------------------------------------------------------------------------ // diff --git a/SampleProject/Motis/MJAppDelegate.m b/SampleProject/Motis/MJAppDelegate.m index e3aae66..cdb8a0c 100644 --- a/SampleProject/Motis/MJAppDelegate.m +++ b/SampleProject/Motis/MJAppDelegate.m @@ -25,7 +25,7 @@ @implementation MJAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - //[self performTest]; // <--- UNCOMMENT FOR TESTING + [self performTest]; // <--- UNCOMMENT FOR TESTING UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; window.rootViewController = [[UIViewController alloc] init]; diff --git a/SampleProject/Motis/MJUser.h b/SampleProject/Motis/MJUser.h index 5d61aa2..50a9912 100644 --- a/SampleProject/Motis/MJUser.h +++ b/SampleProject/Motis/MJUser.h @@ -16,6 +16,8 @@ #import +#import "Motis.h" + @interface MJUser : NSObject @property (nonatomic, assign) NSNumber *userId; diff --git a/SampleProject/Motis/MJVideo.h b/SampleProject/Motis/MJVideo.h index 5468e81..b39dd13 100644 --- a/SampleProject/Motis/MJVideo.h +++ b/SampleProject/Motis/MJVideo.h @@ -16,7 +16,7 @@ #import -@class MJUser; +#import "MJUser.h" /** ********************************************************* ** * @name JSON Entity Attributes @@ -62,8 +62,9 @@ /** * Title of the video. + * @discussion Just for testing porpuses we set the NSString type as an id . **/ -@property (nonatomic, strong) NSString *title; +@property (nonatomic, strong) id title; /** * Description of the video.