今天在混編時(shí)碰到一個(gè)關(guān)于Swift取值的報(bào)錯(cuò)問題,記錄一下。
- 語言環(huán)境:Swift3+、Objective-C混編
- Xcode環(huán)境:9.0
- 報(bào)錯(cuò)場景:
Objective-C中
在OC中實(shí)現(xiàn)了一個(gè)Model類XTNewVoteModel,用作展示數(shù)據(jù)
@interface XTNewVoteModel : NSObject
@property(nonatomic,strong,readwrite) NSString *objectId;
@property(nonatomic,strong,readwrite) NSString *uid;
@property(nonatomic,strong,readwrite) APIUser *user;
@property(nonatomic,strong,readwrite) NSString *content;
@property(nonatomic,strong,readwrite) NSArray *pictures;
@property(nonatomic,assign,readwrite) NSNumber *commentCount;
@property(nonatomic,assign,readwrite) NSNumber *likedCount;
@property(nonatomic,assign,readwrite) BOOL isLiked;
@property(nonatomic,strong,readwrite) NSString *createdAt;
@property(nonatomic,strong,readwrite) NSString *updatedAt;
@end
然后在請求A的封裝類B中利用yymodel解析返回?cái)?shù)據(jù)到XTNewVoteResultInfo
NSString *jsonStr = [request.responseObject objectForKey:RESPONSE_STATUS_DATA_KEY];
XTNewVoteResultInfo *resultInfo = [XTNewVoteResultInfo yy_modelWithJSON:jsonStr];
注:XTNewVoteModel在XTNewVoteResultInfo中的表現(xiàn)為NSArray<XTNewVoteModel *> *list (這是我最終需要的數(shù)據(jù))
即
@interface XTNewVoteResultInfo : NSObject
@property(nonatomic,assign,readwrite) NSInteger total;
@property(nonatomic,strong,readwrite) NSArray<XTNewVoteModel *> *list;
@end
Swift中
在Swift類中調(diào)用網(wǎng)絡(luò)請求類B,并處理返回的數(shù)據(jù)。但是在傳遞參數(shù)時(shí),報(bào)出了如下錯(cuò)誤:
atal error: NSArray element failed to match the Swift Array Element type
這令我十分的費(fèi)解,明明參數(shù)格式、名稱都正確,為什么會(huì)出現(xiàn)這個(gè)error?于是在各種google以及嘗試無功而返后,我決定逐步排查問題,在經(jīng)歷了一個(gè)多小時(shí)的摸爬滾打中,我發(fā)現(xiàn)我在Swift中的數(shù)組元素本應(yīng)該是[XTNewVoteModel]格式的,但是卻顯示的是[Dictionary]類型的,于是我將懷疑范圍逐步縮小到了XTNewVoteModel這個(gè)Model上面。經(jīng)過仔細(xì)排查,我發(fā)現(xiàn)我沒有對這個(gè)Model進(jìn)行映射處理,導(dǎo)致Swift無法對這個(gè)Oc類中的類型進(jìn)行正確的處理。
先說解決方案:
在XTNewVoteResultInfo.m中加入如下兩段代碼即可解決問題:
@implementation XTNewVoteResultInfo
#pragma mark - 字段映射
+ (NSDictionary *)modelCustomPropertyMapper {
return @{
@"list":@"list"
};
}
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{
@"list":[XTNewVoteModel class],
};
}
@end
這兩段代碼就是yymodel中聲明的方法,調(diào)用類通過實(shí)現(xiàn)這些方法,實(shí)現(xiàn)JSON和Model之間轉(zhuǎn)換過程中的特殊處理。
簡單介紹 參考: iOS源碼解析—YYModel(NSObject+YYModel)
1.modelCustomPropertyMapper方法,可以指定json和model轉(zhuǎn)化過程中key的映射關(guān)系,如果存在以下的字典:
NSDictionary *studentDic = @{@"NAME" : @"Tomy",
@"AGE" : @{@"num":@18},
@"college" : @{@"name" : @"NJU"}};
如果需要將studentDic轉(zhuǎn)化成Student類型的model,需要實(shí)現(xiàn)如下modelCustomPropertyMapper方法:
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper
{
return @{@"name" : @"NAME",
@"age" : @"AGE.num"};
}
返回的鍵值對中的key是Student的property名稱,value是studentDic中的key。
2.如果Student中存在property是對象數(shù)組或者字典,實(shí)現(xiàn)modelContainerPropertyGenericClass方法,例如Student存在屬性mobilePhones,維護(hù)一組MobilePhone對象
@interface MobilePhone : NSObject
@property (nonatomic, copy) NSString *brand;
@property (nonatomic, assign) NSInteger phoneNumber;
@end
@interface Student : NSObject <YYModel>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) College *college;
@property (nonatomic, strong) NSArray *mobilePhones; //MobilePhone對象數(shù)組
@end
NSDictionary *studentDic =
@{@"name" : @"Tomy",
@"age" : @18,
@"college" : @{@"name" : @"NJU"},
@"mobilePhones" : @[@{@"brand" : @"iphone",@"phoneNumber" : @123456},
@{@"brand" : @"HUAWEI",@"phoneNumber" : @123456}]};
調(diào)用[Student yy_modelWithDictionary:studentDic]方法將studentDic中的mobilePhones轉(zhuǎn)化成Student的mobilePhones屬性,需要實(shí)現(xiàn)如下:
+ (nullable NSDictionary<NSString*, id>*)modelContainerPropertyGenericClass
{
return @{@"mobilePhones" : [MobilePhone class]};
}