From ec8b81756fdb1bdfc8482ad78078535cce49ebb5 Mon Sep 17 00:00:00 2001 From: sky Date: Mon, 19 Mar 2018 15:19:35 +0800 Subject: [PATCH 1/4] Fix parse issue when genericClass of array is `NSURL` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题根本原因在于,数组解析时,json 数据格式与目标模型格式不匹配 --- YYModel/NSObject+YYModel.m | 23 +++++++++++++++++++++++ YYModelTests/YYTestCustomClass.m | 27 ++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/YYModel/NSObject+YYModel.m b/YYModel/NSObject+YYModel.m index 3d7c470..cb85603 100644 --- a/YYModel/NSObject+YYModel.m +++ b/YYModel/NSObject+YYModel.m @@ -902,6 +902,29 @@ static void ModelSetValueForProperty(__unsafe_unretained id model, for (id one in valueArr) { if ([one isKindOfClass:meta->_genericCls]) { [objectArr addObject:one]; + } else if (meta->_genericCls == [NSString class]) { + if ([one isKindOfClass:[NSNumber class]]) { + [objectArr addObject:((NSNumber *)one).stringValue]; + } + } else if (meta->_genericCls == [NSMutableString class]) { + if ([one isKindOfClass:[NSString class]]) { + [objectArr addObject:((NSString *)one).mutableCopy]; + } else if ([one isKindOfClass:[NSNumber class]]) { + [objectArr addObject:((NSNumber *)one).stringValue.mutableCopy]; + } + } else if (meta->_genericCls == [NSNumber class]) { + [objectArr addObject:YYNSNumberCreateFromID(one)]; + } else if (meta->_genericCls == [NSURL class]) { + if ([one isKindOfClass:[NSURL class]]) { + [objectArr addObject:[NSURL URLWithString:one]]; + } else if ([one isKindOfClass:[NSString class]]) { + NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *str = [one stringByTrimmingCharactersInSet:set]; + if (str.length == 0) { + } else { + [objectArr addObject:[[NSURL alloc] initWithString:str]]; + } + } } else if ([one isKindOfClass:[NSDictionary class]]) { Class cls = meta->_genericCls; if (meta->_hasCustomClassFromDictionary) { diff --git a/YYModelTests/YYTestCustomClass.m b/YYModelTests/YYTestCustomClass.m index 3b69532..7743907 100644 --- a/YYModelTests/YYTestCustomClass.m +++ b/YYModelTests/YYTestCustomClass.m @@ -47,6 +47,11 @@ @interface YYTestCustomClassModel : NSObject @property (nonatomic, strong) NSDictionary *userDict; @property (nonatomic, strong) NSSet *userSet; @property (nonatomic, strong) YYBaseUser *user; +@property (nonatomic, strong) NSArray *imageURLs; +@property (nonatomic, strong) NSArray *phones; +@property (nonatomic, strong) NSArray *editPhones; +@property (nonatomic, strong) NSArray *scores; + @end @implementation YYTestCustomClassModel @@ -54,7 +59,12 @@ @implementation YYTestCustomClassModel + (NSDictionary *)modelContainerPropertyGenericClass { return @{@"users" : YYBaseUser.class, @"userDict" : YYBaseUser.class, - @"userSet" : YYBaseUser.class}; + @"userSet" : YYBaseUser.class, + @"imageURLs" : NSURL.class, + @"phones" : NSString.class, + @"editPhones" : NSMutableString.class, + @"scores" : NSNumber.class, + }; } + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary { if (dictionary[@"localName"]) { @@ -80,6 +90,9 @@ - (void)test { NSDictionary *jsonUserBase = @{@"uid" : @123, @"name" : @"Harry"}; NSDictionary *jsonUserLocal = @{@"uid" : @123, @"name" : @"Harry", @"localName" : @"HarryLocal"}; NSDictionary *jsonUserRemote = @{@"uid" : @123, @"name" : @"Harry", @"remoteName" : @"HarryRemote"}; + NSArray *jsonImageURLs = @[@"http://aaa.com", @"http://bbb.com"]; + NSArray *jsonPhones = @[@13000000001, @13000000002, @13000000003]; + NSArray *jsonScores = @[@"90", @"80", @"70"]; user = [YYBaseUser yy_modelWithDictionary:jsonUserBase]; XCTAssert([user isMemberOfClass:[YYBaseUser class]]); @@ -90,6 +103,18 @@ - (void)test { user = [YYBaseUser yy_modelWithDictionary:jsonUserRemote]; XCTAssert([user isMemberOfClass:[YYRemoteUser class]]); + model = [YYTestCustomClassModel yy_modelWithJSON:@{@"imageURLs" : jsonImageURLs}]; + XCTAssert([model.imageURLs[0] isMemberOfClass:[NSURL class]]); + + model = [YYTestCustomClassModel yy_modelWithJSON:@{@"phones" : jsonPhones}]; + XCTAssert([model.phones[0] isKindOfClass:[NSString class]]); + + model = [YYTestCustomClassModel yy_modelWithJSON:@{@"editPhones" : jsonPhones}]; + XCTAssert([model.editPhones[0] isKindOfClass:[NSMutableString class]]); + + model = [YYTestCustomClassModel yy_modelWithJSON:@{@"scores" : jsonScores}]; + XCTAssert([model.scores[0] isKindOfClass:[NSNumber class]]); + model = [YYTestCustomClassModel yy_modelWithJSON:@{@"user" : jsonUserLocal}]; XCTAssert([model.user isMemberOfClass:[YYLocalUser class]]); From e30d0233a4adf9fc7ab0d4019effe5eb1ade77d0 Mon Sep 17 00:00:00 2001 From: sky Date: Mon, 19 Mar 2018 15:28:57 +0800 Subject: [PATCH 2/4] Update NSObject+YYModel.m fix typo error, one should never be `NSURL` --- YYModel/NSObject+YYModel.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/YYModel/NSObject+YYModel.m b/YYModel/NSObject+YYModel.m index cb85603..54d9821 100644 --- a/YYModel/NSObject+YYModel.m +++ b/YYModel/NSObject+YYModel.m @@ -915,9 +915,7 @@ static void ModelSetValueForProperty(__unsafe_unretained id model, } else if (meta->_genericCls == [NSNumber class]) { [objectArr addObject:YYNSNumberCreateFromID(one)]; } else if (meta->_genericCls == [NSURL class]) { - if ([one isKindOfClass:[NSURL class]]) { - [objectArr addObject:[NSURL URLWithString:one]]; - } else if ([one isKindOfClass:[NSString class]]) { + if ([one isKindOfClass:[NSString class]]) { NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; NSString *str = [one stringByTrimmingCharactersInSet:set]; if (str.length == 0) { From d98763d3a0c40f8d4e0b845b98ece6575f902d43 Mon Sep 17 00:00:00 2001 From: sky Date: Mon, 19 Mar 2018 15:48:42 +0800 Subject: [PATCH 3/4] code coverage issue --- YYModel/NSObject+YYModel.m | 3 +-- YYModelTests/YYTestCustomClass.m | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/YYModel/NSObject+YYModel.m b/YYModel/NSObject+YYModel.m index 54d9821..5902309 100644 --- a/YYModel/NSObject+YYModel.m +++ b/YYModel/NSObject+YYModel.m @@ -918,8 +918,7 @@ static void ModelSetValueForProperty(__unsafe_unretained id model, if ([one isKindOfClass:[NSString class]]) { NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; NSString *str = [one stringByTrimmingCharactersInSet:set]; - if (str.length == 0) { - } else { + if (str.length > 0) { [objectArr addObject:[[NSURL alloc] initWithString:str]]; } } diff --git a/YYModelTests/YYTestCustomClass.m b/YYModelTests/YYTestCustomClass.m index 7743907..09c8a8e 100644 --- a/YYModelTests/YYTestCustomClass.m +++ b/YYModelTests/YYTestCustomClass.m @@ -90,8 +90,8 @@ - (void)test { NSDictionary *jsonUserBase = @{@"uid" : @123, @"name" : @"Harry"}; NSDictionary *jsonUserLocal = @{@"uid" : @123, @"name" : @"Harry", @"localName" : @"HarryLocal"}; NSDictionary *jsonUserRemote = @{@"uid" : @123, @"name" : @"Harry", @"remoteName" : @"HarryRemote"}; - NSArray *jsonImageURLs = @[@"http://aaa.com", @"http://bbb.com"]; - NSArray *jsonPhones = @[@13000000001, @13000000002, @13000000003]; + NSArray *jsonImageURLs = @[@"http://aaa.com", @"http://bbb.com", @""]; + NSArray *jsonPhones = @[@13000000001, @13000000002, @"13000000003"]; NSArray *jsonScores = @[@"90", @"80", @"70"]; user = [YYBaseUser yy_modelWithDictionary:jsonUserBase]; From ea7c19480c288da7dbe2c959f5c74ea5d2bbc1e4 Mon Sep 17 00:00:00 2001 From: sky Date: Mon, 19 Mar 2018 16:52:35 +0800 Subject: [PATCH 4/4] `NSMutableString` issue --- YYModel/NSObject+YYModel.m | 26 +++++++++----------------- YYModelTests/YYTestCustomClass.m | 4 +++- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/YYModel/NSObject+YYModel.m b/YYModel/NSObject+YYModel.m index 5902309..30a26b4 100644 --- a/YYModel/NSObject+YYModel.m +++ b/YYModel/NSObject+YYModel.m @@ -902,25 +902,17 @@ static void ModelSetValueForProperty(__unsafe_unretained id model, for (id one in valueArr) { if ([one isKindOfClass:meta->_genericCls]) { [objectArr addObject:one]; - } else if (meta->_genericCls == [NSString class]) { - if ([one isKindOfClass:[NSNumber class]]) { - [objectArr addObject:((NSNumber *)one).stringValue]; - } - } else if (meta->_genericCls == [NSMutableString class]) { - if ([one isKindOfClass:[NSString class]]) { - [objectArr addObject:((NSString *)one).mutableCopy]; - } else if ([one isKindOfClass:[NSNumber class]]) { - [objectArr addObject:((NSNumber *)one).stringValue.mutableCopy]; - } + } else if (meta->_genericCls == [NSString class] && [one isKindOfClass:[NSNumber class]]) { + [objectArr addObject:((NSNumber *)one).stringValue]; + } else if (meta->_genericCls == [NSMutableString class] && [one isKindOfClass:[NSNumber class]]) { + [objectArr addObject:((NSNumber *)one).stringValue.mutableCopy]; } else if (meta->_genericCls == [NSNumber class]) { [objectArr addObject:YYNSNumberCreateFromID(one)]; - } else if (meta->_genericCls == [NSURL class]) { - if ([one isKindOfClass:[NSString class]]) { - NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - NSString *str = [one stringByTrimmingCharactersInSet:set]; - if (str.length > 0) { - [objectArr addObject:[[NSURL alloc] initWithString:str]]; - } + } else if (meta->_genericCls == [NSURL class] && [one isKindOfClass:[NSString class]]) { + NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *str = [one stringByTrimmingCharactersInSet:set]; + if (str.length > 0) { + [objectArr addObject:[[NSURL alloc] initWithString:str]]; } } else if ([one isKindOfClass:[NSDictionary class]]) { Class cls = meta->_genericCls; diff --git a/YYModelTests/YYTestCustomClass.m b/YYModelTests/YYTestCustomClass.m index 09c8a8e..e8b17be 100644 --- a/YYModelTests/YYTestCustomClass.m +++ b/YYModelTests/YYTestCustomClass.m @@ -110,7 +110,9 @@ - (void)test { XCTAssert([model.phones[0] isKindOfClass:[NSString class]]); model = [YYTestCustomClassModel yy_modelWithJSON:@{@"editPhones" : jsonPhones}]; - XCTAssert([model.editPhones[0] isKindOfClass:[NSMutableString class]]); + //__NSCFConstantString->__NSCFString->NSMutableString->NSString + //model.editPhones[2]不是 NSMutableString,使用 `appendString:` 会导致 crash + XCTAssert([model.editPhones[2] isKindOfClass:[NSMutableString class]]); model = [YYTestCustomClassModel yy_modelWithJSON:@{@"scores" : jsonScores}]; XCTAssert([model.scores[0] isKindOfClass:[NSNumber class]]);