前言
本文的中文注释代码demo更新在我的github上。
上篇 YYModel源代码分析(二)YYClassInfo
主要分析了YYClassInfo文件。本篇会主要集中在NSObject+YYModel文件上。文章内容会包含一些与JSONModel的比较,想了解JSONModel,可以参考JSONModel源代码解析。
主体分层
NSObject+YYModel主要分为以下几个部分:
- 内部使用的C函数部分
@interface _YYModelPropertyMeta : NSObject
@interface _YYModelMeta : NSObject
@interface NSObject (YYModel) : NSObject
@interface NSArray (YYModel) : NSObject
@interface NSDictionary (YYModel) : NSObject
@protocol YYModel <NSObject>
:接口YYModel
由于代码较多,所以会挑重点的部分进行介绍。
NSObject+YYModel源代码
@interface _YYModelPropertyMeta : NSObject
声明
/// A property info in object model.
// model property的进一步分装
@interface _YYModelPropertyMeta : NSObject {
@package
NSString *_name; ///< property's name //property名
YYEncodingType _type; ///< property's type //property的encode解析值
YYEncodingNSType _nsType; ///< property's Foundation type //property的foundation类型
BOOL _isCNumber; ///< is c number type //是不是c语言的数字
Class _cls; ///< property's class, or nil //property的class
Class _genericCls; ///< container's generic class, or nil if threr's no generic class //property内包含的类class
SEL _getter; ///< getter, or nil if the instances cannot respond //property getter方法
SEL _setter; ///< setter, or nil if the instances cannot respond //property setter方法
BOOL _isKVCCompatible; ///< YES if it can access with key-value coding //是否可以使用KVC
BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver //是否是struct并且可以archiver/unarchiver
BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary: //是否包含本本地的class转换
/*
property->key: _mappedToKey:key _mappedToKeyPath:nil _mappedToKeyArray:nil
property->keyPath: _mappedToKey:keyPath _mappedToKeyPath:keyPath(array) _mappedToKeyArray:nil
property->keys: _mappedToKey:keys[0] _mappedToKeyPath:nil/keyPath _mappedToKeyArray:keys(array)
*/
NSString *_mappedToKey; ///< the key mapped to //property本地的key mapper的key
NSArray *_mappedToKeyPath; ///< the key path mapped to (nil if the name is not key path) //property本地的key mapper的key path列表
NSArray *_mappedToKeyArray; ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys) /property本地的key mapper的key列表
YYClassPropertyInfo *_info; ///< property's info //property的YYClassPropertyInfo info
_YYModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key. //同个key的多个property的映射next指针
}
@end
其中需要理解一下的包括:
1._hasCustomClassFromDictionary
就是判断是否有本地的不同class的映射
如下例子,当dictionary包含不同的值的时候,映射的model类型不同
@implementation YYBaseUser
+ (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
if (dictionary[@"localName"]) {
return [YYLocalUser class];
} else if (dictionary[@"remoteName"]) {
return [YYRemoteUser class];
}
return [YYBaseUser class];
}
2.keyMapper相关内容
如下例子,dictionary中不同的key,对应的model的property有一个映射关系
其中对于包含”.”的映射,则是一种多层的映射关系
+ (NSDictionary *)modelCustomPropertyMapper {
return @{ @"name" : @"n",
@"count" : @"ext.c",
@"desc1" : @"ext.d", // mapped to same key path
@"desc2" : @"ext.d", // mapped to same key path
@"desc3" : @"ext.d.e",
@"desc4" : @".ext",
@"modelID" : @[@"ID", @"Id", @"id", @"ext.id"]};
}
3._YYModelPropertyMeta *_next
同一个key的下一个meta解析类型
因为有了key mapper,所以会出现同一个mapper的key值,可能会一对多个model的property值,这边设计了一个_next指针进行链接
4.Class _genericCls
包含的类型
如下例子,property会有NSArray\NSDictionary\NSSet类型,内部的类型就通过该参数表示
@interface YYTestCustomClassModel : NSObject
@property (nonatomic, strong) NSArray *users;
@property (nonatomic, strong) NSDictionary *userDict;
@property (nonatomic, strong) NSSet *userSet;
@end
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"users" : YYBaseUser.class,
@"userDict" : YYBaseUser.class,
@"userSet" : YYBaseUser.class};
}
实现
//通过YYClassInfo,YYClassPropertyInfo,Class对象解析成_YYModelPropertyMeta
+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic {
// support pseudo generic class with protocol name
// 这边也考虑了,某些类型写在protocol中,包含在<>中,和JSONModel一样进行一下protocol的类型判断
// 比如NSArray<TestObject> xxx
if (!generic && propertyInfo.protocols) {
for (NSString *protocol in propertyInfo.protocols) {
Class cls = objc_getClass(protocol.UTF8String);
if (cls) {
generic = cls;
break;
}
}
}
//构造_YYModelPropertyMeta对象
_YYModelPropertyMeta *meta = [self new];
meta->_name = propertyInfo.name; //设置名
meta->_type = propertyInfo.type; //设置encode type
meta->_info = propertyInfo; //设置YYClassPropertyI