Skip to content

Commit

Permalink
support pseudo generic class with protocol name
Browse files Browse the repository at this point in the history
  • Loading branch information
ibireme committed Jun 12, 2016
1 parent 3760272 commit 6136b54
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 9 deletions.
12 changes: 12 additions & 0 deletions YYModel/NSObject+YYModel.m
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions YYModel/YYClassInfo.h
Expand Up @@ -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<NSString *> *protocols; ///< may nil
@property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull)
@property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull)

Expand Down
28 changes: 21 additions & 7 deletions YYModel/YYClassInfo.m
Expand Up @@ -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;
Expand Down
37 changes: 35 additions & 2 deletions YYModelTests/YYTestModelMapper.m
Expand Up @@ -55,13 +55,31 @@ @implementation YYTestPropertyMapperModelWarn
@end






@protocol YYTestPropertyMapperModelAuto <NSObject>
@end

@protocol YYTestPropertyMapperModelCustom <NSObject>
@end

@protocol YYSimpleProtocol <NSObject>
@end


@interface YYTestPropertyMapperModelContainer : NSObject
@property (nonatomic, strong) NSArray *array;
@property (nonatomic, strong) NSMutableArray *mArray;
@property (nonatomic, strong) NSDictionary *dict;
@property (nonatomic, strong) NSMutableDictionary *mDict;
@property (nonatomic, strong) NSSet *set;
@property (nonatomic, strong) NSMutableSet *mSet;

@property (nonatomic, strong) NSArray<YYTestPropertyMapperModelAuto> *pArray1;
@property (nonatomic, strong) NSArray<YYSimpleProtocol,YYTestPropertyMapperModelAuto> *pArray2;
@property (nonatomic, strong) NSArray<YYSimpleProtocol,YYTestPropertyMapperModelCustom> *pArray3;
@end

@implementation YYTestPropertyMapperModelContainer
Expand All @@ -74,15 +92,19 @@ @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,
@"mArray" : YYTestPropertyMapperModelAuto.class,
@"dict" : YYTestPropertyMapperModelAuto.class,
@"mDict" : YYTestPropertyMapperModelAuto.class,
@"set" : @"YYTestPropertyMapperModelAuto",
@"mSet" : @"YYTestPropertyMapperModelAuto"};
@"mSet" : @"YYTestPropertyMapperModelAuto",
@"pArray3" : @"YYTestPropertyMapperModelAuto"};
}
@end

Expand Down Expand Up @@ -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]]);

Expand Down

0 comments on commit 6136b54

Please sign in to comment.