From 6136b54598335723df97c5a7b329973f7163e113 Mon Sep 17 00:00:00 2001 From: ibireme Date: Mon, 13 Jun 2016 01:55:17 +0800 Subject: [PATCH] support pseudo generic class with protocol name --- YYModel/NSObject+YYModel.m | 12 +++++++++++ YYModel/YYClassInfo.h | 1 + YYModel/YYClassInfo.m | 28 ++++++++++++++++++------ YYModelTests/YYTestModelMapper.m | 37 ++++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/YYModel/NSObject+YYModel.m b/YYModel/NSObject+YYModel.m index 74fd520..e92a6b1 100644 --- a/YYModel/NSObject+YYModel.m +++ b/YYModel/NSObject+YYModel.m @@ -346,6 +346,18 @@ @interface _YYModelPropertyMeta : NSObject { @implementation _YYModelPropertyMeta + (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic { + + // support pseudo generic class with protocol name + if (!generic && propertyInfo.protocols) { + for (NSString *protocol in propertyInfo.protocols) { + Class cls = objc_getClass(protocol.UTF8String); + if (cls) { + generic = cls; + break; + } + } + } + _YYModelPropertyMeta *meta = [self new]; meta->_name = propertyInfo.name; meta->_type = propertyInfo.type; diff --git a/YYModel/YYClassInfo.h b/YYModel/YYClassInfo.h index a74e96f..6b87458 100644 --- a/YYModel/YYClassInfo.h +++ b/YYModel/YYClassInfo.h @@ -128,6 +128,7 @@ YYEncodingType YYEncodingGetType(const char *typeEncoding); @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value @property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil +@property (nullable, nonatomic, strong, readonly) NSArray *protocols; ///< may nil @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull) @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) diff --git a/YYModel/YYClassInfo.m b/YYModel/YYClassInfo.m index 4a8415f..16df6d9 100644 --- a/YYModel/YYClassInfo.m +++ b/YYModel/YYClassInfo.m @@ -168,14 +168,28 @@ - (instancetype)initWithProperty:(objc_property_t)property { if (attrs[i].value) { _typeEncoding = [NSString stringWithUTF8String:attrs[i].value]; type = YYEncodingGetType(attrs[i].value); - if ((type & YYEncodingTypeMask) == YYEncodingTypeObject) { - size_t len = strlen(attrs[i].value); - if (len > 3) { - char name[len - 2]; - name[len - 3] = '\0'; - memcpy(name, attrs[i].value + 2, len - 3); - _cls = objc_getClass(name); + + if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) { + NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding]; + if (![scanner scanString:@"@\"" intoString:NULL]) continue; + + NSString *clsName = nil; + if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) { + if (clsName.length) _cls = objc_getClass(clsName.UTF8String); } + + NSMutableArray *protocols = nil; + while ([scanner scanString:@"<" intoString:NULL]) { + NSString* protocol = nil; + if ([scanner scanUpToString:@">" intoString: &protocol]) { + if (protocol.length) { + if (!protocols) protocols = [NSMutableArray new]; + [protocols addObject:protocol]; + } + } + [scanner scanString:@">" intoString:NULL]; + } + _protocols = protocols; } } } break; diff --git a/YYModelTests/YYTestModelMapper.m b/YYModelTests/YYTestModelMapper.m index 70552fa..4b52c8d 100644 --- a/YYModelTests/YYTestModelMapper.m +++ b/YYModelTests/YYTestModelMapper.m @@ -55,6 +55,20 @@ @implementation YYTestPropertyMapperModelWarn @end + + + + +@protocol YYTestPropertyMapperModelAuto +@end + +@protocol YYTestPropertyMapperModelCustom +@end + +@protocol YYSimpleProtocol +@end + + @interface YYTestPropertyMapperModelContainer : NSObject @property (nonatomic, strong) NSArray *array; @property (nonatomic, strong) NSMutableArray *mArray; @@ -62,6 +76,10 @@ @interface YYTestPropertyMapperModelContainer : NSObject @property (nonatomic, strong) NSMutableDictionary *mDict; @property (nonatomic, strong) NSSet *set; @property (nonatomic, strong) NSMutableSet *mSet; + +@property (nonatomic, strong) NSArray *pArray1; +@property (nonatomic, strong) NSArray *pArray2; +@property (nonatomic, strong) NSArray *pArray3; @end @implementation YYTestPropertyMapperModelContainer @@ -74,7 +92,10 @@ @implementation YYTestPropertyMapperModelContainerGeneric + (NSDictionary *)modelCustomPropertyMapper { return @{ @"mArray" : @"array", @"mDict" : @"dict", - @"mSet" : @"set"}; + @"mSet" : @"set", + @"pArray1" : @"array", + @"pArray2" : @"array", + @"pArray3" : @"array"}; } + (NSDictionary *)modelContainerPropertyGenericClass { return @{@"array" : YYTestPropertyMapperModelAuto.class, @@ -82,7 +103,8 @@ + (NSDictionary *)modelContainerPropertyGenericClass { @"dict" : YYTestPropertyMapperModelAuto.class, @"mDict" : YYTestPropertyMapperModelAuto.class, @"set" : @"YYTestPropertyMapperModelAuto", - @"mSet" : @"YYTestPropertyMapperModelAuto"}; + @"mSet" : @"YYTestPropertyMapperModelAuto", + @"pArray3" : @"YYTestPropertyMapperModelAuto"}; } @end @@ -198,6 +220,17 @@ - (void)testContainer { XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.array[2]).count isEqual:@12]); XCTAssertTrue([model.mArray isKindOfClass:[NSMutableArray class]]); + XCTAssertTrue(model.pArray1.count == 3); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray1[0]).name isEqualToString:@"Apple"]); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray1[0]).count isEqual:@10]); + XCTAssertTrue(model.pArray2.count == 3); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray2[0]).name isEqualToString:@"Apple"]); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray2[0]).count isEqual:@10]); + XCTAssertTrue(model.pArray3.count == 3); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray3[0]).name isEqualToString:@"Apple"]); + XCTAssertTrue([((YYTestPropertyMapperModelAuto *)model.pArray3[0]).count isEqual:@10]); + + jsonObject = [model yy_modelToJSONObject]; XCTAssertTrue([jsonObject[@"array"] isKindOfClass:[NSArray class]]);