項(xiàng)目地址點(diǎn)這里......
學(xué)習(xí)NSObject+YYModel之前要先了學(xué)一下他YYClassInfo類.
如果runtime有了解過(guò)沧卢,就會(huì)發(fā)現(xiàn)yyclassinfo 是對(duì)ivar尊搬,method颖变,objc_property婴渡,class這三個(gè)做了整理歸納定義堪置,對(duì)應(yīng)YYClassIvarInfo媒熊,YYClassMethodInfo,YYClassPropertyInfo,YYClassInfo更容易看懂他們每個(gè)類所擁有的特性,也更方便的直接的使用惭每。他們的實(shí)現(xiàn)也是基于Runtime,具體可以看YYKit
的源碼.
參考:http://www.reibang.com/p/36273f598731
開始學(xué)習(xí)NSObject+YYModel
#define force_inline __inline__ __attribute__((always_inline))
定義內(nèi)聯(lián)函數(shù)
獲取這個(gè)屬性的類型信息
static force_inline YYEncodingNSType YYClassGetNSType(Class cls){}
是否是number型亏栈,基本類型
static force_inline BOOL YYEncodingTypeIsCNumber(YYEncodingType type)
從id中解析nsnumber類型 不是很懂
static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value){}
字符串轉(zhuǎn)化為date類型
static force_inline NSDate *YYNSDateFromString(__unsafe_unretained NSString *string) {}
定義NSBlock類
static force_inline Class YYNSBlockClass(){}
獲取國(guó)際標(biāo)準(zhǔn)化組織的日期格式
static force_inline NSDateFormatter *YYISODateFormatter() {}
獲取字典里面一序列鍵值對(duì)應(yīng)的值
static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {}
獲取字典里面一序列鍵值對(duì)應(yīng)的值 感覺(jué)跟上面一個(gè)方法沒(méi)什么差
static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {}
通過(guò)屬性獲取number
static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model, __unsafe_unretained _YYModelPropertyMeta *meta) {}
設(shè)置number到屬性
static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
__unsafe_unretained NSNumber *num,
__unsafe_unretained _YYModelPropertyMeta *meta) {}
設(shè)置值與屬性的元模型台腥。
static void ModelSetValueForProperty(__unsafe_unretained id model,
__unsafe_unretained id value,
__unsafe_unretained _YYModelPropertyMeta *meta) {}
應(yīng)用函數(shù)字典,設(shè)置鍵-值對(duì)模型。
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {}
應(yīng)用屬性元函數(shù)模型,設(shè)置字典模型绒北。
static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {}
將模型轉(zhuǎn)化成json串
static id ModelToJSONObjectRecursive(NSObject *model) {}
增加縮進(jìn)字符串(排除第一行)
static NSMutableString *ModelDescriptionAddIndent(NSMutableString *desc, NSUInteger indent) {}
模型生成一個(gè)字符串描述
static NSString *ModelDescription(NSObject *model) {}
NSObject+YYModel
1.+ (NSDictionary *)_yy_dictionaryWithJSON:(id)json {}
將傳進(jìn)來(lái)的json類型轉(zhuǎn)化為字典
2.+ (instancetype)modelWithJSON:(id)json {}
通過(guò)傳進(jìn)來(lái)的json實(shí)例該類對(duì)象黎侈,通過(guò) modelWithDictionary轉(zhuǎn)化
3.+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary {}
- 通過(guò)私有類_YYModelMeta(模型元件)將該類中的屬性,變量闷游,方法峻汉,映射信息都提取出來(lái) 在其中_YYModelMeta中:
類的基本信息
YYClassInfo *_classInfo;
屬性信息和_YYModelPropertyMeta屬性類的映射
NSDictionary *_mapper;
所有屬性對(duì)象的數(shù)組,每個(gè)元素是_YYModelPropertyMeta類型
NSArray *_allPropertyMetas;
所有屬性對(duì)應(yīng)的keypath的映射的數(shù)組储藐,每個(gè)屬性類型也都是_YYModelPropertyMeta類型
NSArray *_keyPathPropertyMetas;
有多個(gè)key映射
NSArray *_multiKeysPropertyMetas;
映射的數(shù)量
NSUInteger _keyMappedCount;
類編碼類型
YYEncodingNSType _nsType;
是否執(zhí)行 modelCustomWillTransformFromDictionary 自定義對(duì)象將要轉(zhuǎn)化為模型的時(shí)候,如果有實(shí)現(xiàn)該方法俱济,他將先于 `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` 和 `-modelSetWithDictionary:`這些方法執(zhí)行嘶是,返回是一個(gè)字典類型.
BOOL _hasCustomWillTransformFromDictionary;
是否執(zhí)行 modelCustomTransformFromDictionary, 返回的是一個(gè)布爾值钙勃,如果是默認(rèn)的json-to-model轉(zhuǎn)化的時(shí)候某個(gè)字段適合你的自定義的模型,可以去實(shí)現(xiàn)這個(gè)額外的方法,你也可以使用這個(gè)方法來(lái)校驗(yàn)?zāi)銓傩缘念愋湍衾祷豗ES這個(gè)模型是可用的辖源,NO則不可用,具體看例子實(shí)現(xiàn)
BOOL _hasCustomTransformFromDictionary;
是否執(zhí)行 modelCustomTransformToDictionary希太,如果是默認(rèn)的json-to-model轉(zhuǎn)化的時(shí)候某個(gè)字段適合你的自定義的模型,返回YES這個(gè)模型是可用的克饶,NO則不可用,具體看例子實(shí)現(xiàn)
BOOL _hasCustomTransformToDictionary;
是否執(zhí)行 modelCustomClassForDictionary誊辉,在json-to-model轉(zhuǎn)化的時(shí)候矾湃,通過(guò)該方法去實(shí)例不同的類類型
BOOL _hasCustomClassFromDictionary;
在YYModeleMeta中的司機(jī)BOOL類型的賦值通過(guò)instancesRespondToSelector
和respondsToSelector
來(lái)做判斷是否實(shí)現(xiàn)對(duì)應(yīng)的方法
他們的區(qū)別參考:
http://www.reibang.com/p/ae494b5eeb86
http://www.reibang.com/p/c37f5d97b07e
http://blog.csdn.net/yxwlzsh/article/details/49755823
instancesRespondToSelector是類方法,用于判斷實(shí)例后的對(duì)象是否綁定某個(gè)方法堕澄,只能用來(lái)判斷實(shí)例方法邀跃。作用于類
類名 + 實(shí)例方法
respondsToSelector是實(shí)例方法霉咨,用于判斷實(shí)例后的對(duì)象是否綁定某個(gè)方法,和類是否實(shí)現(xiàn)某個(gè)類方法拍屑,作用于對(duì)象和類
類名 + 類方法
實(shí)例之后的對(duì)象 + 實(shí)例方法
所有在上面前三個(gè)BOOL是直接通過(guò)類名來(lái)判斷實(shí)例方法所以使用instancesRespondToSelector
,最后一個(gè)是直接判斷類方法所以使用respondsToSelector
回到Y(jié)YKit的model
- 通過(guò)_hasCustomClassFromDictionary判斷是否有自定義類途戒,YES則執(zhí)行modelCustomClassForDictionary
modelCustomClassForDictionary
是用戶自己在外部實(shí)現(xiàn)的方法,傳遞自己要實(shí)例的類類型僵驰。
- 通過(guò)確定的class類new一個(gè)對(duì)象喷斋,通過(guò)modelSetWithDictionary方法實(shí)現(xiàn)dic-to-model
4.- (BOOL)modelSetWithJSON:(id)json {}
判斷這個(gè)json是否可轉(zhuǎn)化成對(duì)象
5.- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {}
實(shí)現(xiàn)Dictionary-To-Model
- 通過(guò)該類實(shí)例_YYModeMeta類型
- 如果沒(méi)有鍵映射的count是0則不能實(shí)例,返回空蒜茴,如果是集成NSObject的模型的話至少有一個(gè)isa的地址的鍵值映射星爪,一般都會(huì)有
- 判斷是否
_hasCustomWillTransformFromDictionary
值,YES則執(zhí)行modelCustomWillTransformFromDictionary - 定義結(jié)構(gòu)體ModelSetContext粉私,其中modelMeta存_YYModelMeta實(shí)例的model移必,model該類實(shí)例的對(duì)象,dictionary要轉(zhuǎn)化的字典類型
- 給模型賦值的過(guò)程用到了CoreFoundation相關(guān)知識(shí)毡鉴,不是很清楚崔泵,后面學(xué)習(xí)一下,先跳過(guò)猪瞬。
- 轉(zhuǎn)化完成之后憎瘸,_hasCustomTransformFromDictionary判斷是否要自動(dòng)已轉(zhuǎn)化從字典中,YES執(zhí)行modelCustomTransformFromDictionary
6.- (id)modelToJSONObject {}
將模型轉(zhuǎn)化為NSArray或者NSDictionary類型陈瘦,其中里面所有的對(duì)象都是通過(guò) NSString, NSNumber, NSArray, NSDictionary, or NSNull.實(shí)例的幌甘,可直接轉(zhuǎn)化為json數(shù)據(jù)
7.- (NSData *)modelToJSONData {}
將對(duì)象轉(zhuǎn)化成Data數(shù)據(jù)
8.- (NSString *)modelToJSONString {}
將對(duì)象轉(zhuǎn)化成json字符串
9.- (id)modelCopy{}
拷貝復(fù)制對(duì)象
10.- (void)modelEncodeWithCoder:(NSCoder *)aCoder {}
和- (id)modelInitWithCoder:(NSCoder *)aDecoder {}
實(shí)現(xiàn)NSCoding編碼解碼,使用的時(shí)候:
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[self modelEncodeWithCoder:aCoder];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
return [self modelInitWithCoder:aDecoder];
}
一句編碼解碼
11.- (NSUInteger)modelHash {}
model哈希
12.- (BOOL)modelIsEqual:(id)model {}
兩個(gè)model是否一樣痊项,
如果地址指針是否一樣或者里面的所有的屬性信息值都是否一樣
13.- (NSString *)modelDescription {}
該類的字符串描述
例子(具體可以看YYKit
里面的YYModelExample
):
NSArray+YYModel
+ (NSArray *)modelArrayWithClass:(Class)cls json:(id)json {}
如果json串可轉(zhuǎn)化成數(shù)組類型锅风,將這個(gè)json數(shù)組中的每個(gè)元素轉(zhuǎn)化成cls類型元素,重新轉(zhuǎn)成變成數(shù)組返回鞍泉,數(shù)組中的元素都是cls類型皱埠。
NSDictionary+YYModel
+ (NSDictionary *)modelDictionaryWithClass:(Class)cls json:(id)json {}
跟數(shù)組的YYModel一樣,key對(duì)應(yīng)的value轉(zhuǎn)化成cls類型value
@protocol YYModel
該協(xié)議不需要去集成添加咖驮,是為了方法的擴(kuò)展边器。為了轉(zhuǎn)模型的時(shí)候更好的定義。
1.+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
自定義屬性的映射托修。如果JSON或者Dic的key在model中找不到對(duì)應(yīng)的關(guān)聯(lián)屬性忘巧,可以用這個(gè)方法添加映射.
Example:
json:
{
"n":"Harry Pottery",
"p": 256,
"ext" : {
"desc" : "A book written by J.K.Rowling."
},
"ID" : 100010
}
model:
@interface YYBook : NSObject
@property NSString *name;
@property NSInteger page;
@property NSString *desc;
@property NSString *bookID;
@end
@implementation YYBook
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"name" : @"n",
@"page" : @"p",
@"desc" : @"ext.desc",
@"bookID": @[@"id", @"ID", @"book_id"]};
}
@end
屬性name
的值對(duì)應(yīng)的是Json中的n
的key的鍵值,
屬性page
的值對(duì)應(yīng)的是Json中的p
的key的鍵值睦刃,
屬性desc
的值對(duì)應(yīng)的是Json中的ext.desc
的key的鍵值砚嘴,其中ext.desc是路徑的key,多層的話 ext.s1.s2.s3...
屬性bookID
的值對(duì)應(yīng)的是Json中的id
、ID
,book_id
的key的鍵值际长,多個(gè)key的值都是對(duì)應(yīng)的bookID的屬性婆誓,可以用數(shù)組的方法傳值。很貼心啊也颤。
2.+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
屬性內(nèi)包含的對(duì)象自定義洋幻,如果一個(gè)屬性是一個(gè)容器的對(duì)象,比如是NSArray/NSSet/NSDictionary翅娶,實(shí)現(xiàn)這個(gè)方法返回對(duì)應(yīng)屬性的映射文留,知道哪一個(gè)類將被添加到容器中,容器中的對(duì)象是哪一種類類型竭沫。
Example:
@class YYShadow, YYBorder, YYAttachment;
@interface YYAttributes
@property NSString *name;
@property NSArray *shadows;
@property NSSet *borders;
@property NSDictionary *attachments;
@end
@implementation YYAttributes
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"shadows" : [YYShadow class],
@"borders" : YYBorder.class,
@"attachments" : @"YYAttachment" };
}
@end
其中這個(gè)類中有三個(gè)是容器的屬性類型燥翅。shadows中是YYShadow元素類型,borders是YYBorder元素類型蜕提,NSDictionary是YYAttachment元素類型森书。自定義類型寫法的時(shí)候可以有這個(gè)三種寫法:[YYShadow class]
,YYBorder.class
,@"YYAttachment"
.
3.+ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;
上面講過(guò),根據(jù)dic來(lái)實(shí)例不通的類類型
Example:
@class YYCircle, YYRectangle, YYLine;
@implementation YYShape
+ (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary {
if (dictionary[@"radius"] != nil) {
return [YYCircle class];
} else if (dictionary[@"width"] != nil) {
return [YYRectangle class];
} else if (dictionary[@"y2"] != nil) {
return [YYLine class];
} else {
return [self class];
}
}
@end
4.+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
哪些屬性在模型轉(zhuǎn)化的過(guò)程中將被忽略,黑名單
5.+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
不在這個(gè)屬性列表中的屬性模型轉(zhuǎn)化過(guò)程中將被忽略谎势,白名單
例子
- 普通對(duì)象實(shí)例
YHBook * book = [YHBook modelWithJSON:@" \
{ \
\"name\": \"Harry Potter\", \
\"pages\": 512, \
\"publishDate\": \"2010-01-01\" \
}"];
NSLog(@"name = %@__date = %@",book.name,book.publishDate);
NSLog(@"BOOk : %@",[book modelToJSONString]);
如果是直接使用modewithJson的時(shí)候沒(méi)有實(shí)現(xiàn)其他的自定義方法的時(shí)候YHBook中定義的屬性的名字需和json串中每個(gè)字段對(duì)應(yīng)的key的名字一樣凛膏。
- 內(nèi)嵌對(duì)象實(shí)例
YYRepo * repo = [YYRepo modelWithJSON:@" \
{ \
\"rid\": 123456789, \
\"name\": \"YYKit\", \
\"createTime\" : \"2011-06-09T06:24:26Z\", \
\"owner\": { \
\"uid\" : 989898, \
\"name\" : \"ibireme\" \
} \
}"];
NSLog(@"owner name %@",repo.owner.name);
NSLog(@"Repo: %@", [repo modelToJSONString]);
json串中在ownerkey這邊有一個(gè)新的一級(jí)字典數(shù)據(jù),外面一層通過(guò)YYRepo來(lái)實(shí)例脏榆,owner這邊通過(guò)YYUser來(lái)實(shí)例猖毫。
- 有屬性是容器類型的屬性,定義該屬性中元素類類型的實(shí)例
@interface YYPhoto : NSObject
@property (nonatomic, copy) NSString *url;
@property (nonatomic, copy) NSString *desc;
@end
@implementation YYPhoto
@end
@interface YYAlbum : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSArray *photos; // Array<YYPhoto>
@property (nonatomic, strong) NSDictionary *likedUsers; // Key:name(NSString) Value:user(YYUser)
@property (nonatomic, strong) NSSet *likedUserIds; // Set<NSNumber>
@end
@implementation YYAlbum
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"photos" : YYPhoto.class,
@"likedUsers" : YYUser.class,
@"likedUserIds" : NSNumber.class};
}
@end
static void ContainerObjectExample() {
YYAlbum *album = [YYAlbum modelWithJSON:@" \
{ \
\"name\" : \"Happy Birthday\", \
\"photos\" : [ \
{ \
\"url\":\"http://example.com/1.png\", \
\"desc\":\"Happy~\" \
}, \
{ \
\"url\":\"http://example.com/2.png\", \
\"desc\":\"Yeah!\" \
} \
], \
\"likedUsers\" : { \
\"Jony\" : {\"uid\":10001,\"name\":\"Jony\"}, \
\"Anna\" : {\"uid\":10002,\"name\":\"Anna\"} \
}, \
\"likedUserIds\" : [10001,10002] \
}"];
NSString *albumJSON = [album modelToJSONString];
NSLog(@"Album: %@", albumJSON);
}
通過(guò)+ (NSDictionary *)modelContainerPropertyGenericClass{}
來(lái)定義photos须喂、photos吁断、likedUserIds這三個(gè)屬性中其元素的類類型.
- NSCoding編碼、解碼坞生, NSCopying拷貝,哈希轉(zhuǎn)化
@interface YYShadow :NSObject <NSCoding, NSCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) UIColor *color;
@end
@implementation YYShadow
- (void)encodeWithCoder:(NSCoder *)aCoder { [self modelEncodeWithCoder:aCoder]; }
- (id)initWithCoder:(NSCoder *)aDecoder { return [self modelInitWithCoder:aDecoder]; }
- (id)copyWithZone:(NSZone *)zone { return [self modelCopy]; }
- (NSUInteger)hash { return [self modelHash]; }
- (BOOL)isEqual:(id)object { return [self modelIsEqual:object]; }
@end
static void CodingCopyingHashEqualExample() {
YYShadow *shadow = [YYShadow new];
shadow.name = @"Test";
shadow.size = CGSizeMake(10, 0);
shadow.color = [UIColor blueColor];
YYShadow *shadow2 = [shadow deepCopy]; // Archive and Unachive
// shadow2.name = @"TT";
BOOL equal = [shadow isEqual:shadow2];
NSLog(@"shadow equals: %@",equal ? @"YES" : @"NO");
}