IOSノート:JSON->ModelのYYYModelソースを1つ削除してノートを読む
8057 ワード
YYModelソース読み取りノート:最初に呼び出す
1. + (instancetype)modelWithJSON:(id)json;
2. + (NSDictionary *)_yy_dictionaryWithJSON:(id)json;
3.- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
3.1 [_YYModelMeta metaWithClass:object_getClass(self)]; 初期化方法
3.2 ModelSetWithDictionaryFunctionベースのdictionary回転モデル
3.3 ModelSetWithPropertyMetaArrayFunction複雑なモード回転モデル
3.4 ModelSetValueForProperty
1. + (instancetype)modelWithJSON:(id)json;
+ (instancetype)modelWithJSON:(id)json {
// NSDictionary ,
// NSString,NSData,NSDictionary
NSDictionary *dic = [self _yy_dictionaryWithJSON:json];
// jsos->model
return [self modelWithDictionary:dic];
}
2. + (NSDictionary *)_yy_dictionaryWithJSON:(id)json;
// NSDictionary
+ (NSDictionary *)_yy_dictionaryWithJSON:(id)json {
//json (kCFNull NSNULL )
if (!json || json == (id)kCFNull) return nil;
NSDictionary *dic = nil;
NSData *jsonData = nil;
//
if ([json isKindOfClass:[NSDictionary class]]) {
dic = json;
} else if ([json isKindOfClass:[NSString class]]) { // , NSData
jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
} else if ([json isKindOfClass:[NSData class]]) { // data,
jsonData = json;
}
if (jsonData) { // data NSDictionary
dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
}
return dic;
}
3.- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {
if (!dic || dic == (id)kCFNull) return NO; //
if (![dic isKindOfClass:[NSDictionary class]]) return NO; //
// model
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
// key->property
if (modelMeta->_keyMappedCount == 0) return NO;
// ,
if (modelMeta->_hasCustomWillTransformFromDictionary) {
dic = [((id)self) modelCustomWillTransformFromDictionary:dic];
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
}
//
ModelSetContext context = {0};
//model
context.modelMeta = (__bridge void *)(modelMeta);
//model
context.model = (__bridge void *)(self);
//model
context.dictionary = (__bridge void *)(dic);
//CFDictionaryApplyFunction / CFArrayApplyFunction
// dictionary / array
//
// model property
if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
// json->model : @{@"name":@"henry"};
CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
// modelCustomPropertyMapper ,
if (modelMeta->_keyPathPropertyMetas) {
/**
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"name" : @"n",
@"page" : @"p",
@"desc" : @"ext.desc",
@"bookID": @[@"id", @"ID", @"book_id"]};
}
*/
// @{@"desc" : @"ext.desc"}
CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
// @{@"bookID": @[@"id", @"ID", @"book_id"]}
if (modelMeta->_multiKeysPropertyMetas) {
CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
} else {
// property
CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
CFRangeMake(0, modelMeta->_keyMappedCount),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
// ,( )
if (modelMeta->_hasCustomTransformFromDictionary) {
return [((id)self) modelCustomTransformFromDictionary:dic];
}
return YES;
}
3.1 [_YYModelMeta metaWithClass:object_getClass(self)]; 初期化方法
/// Returns the cached model class meta
+ (instancetype)metaWithClass:(Class)cls {
if (!cls) return nil;
static CFMutableDictionaryRef cache;
static dispatch_once_t onceToken;
static dispatch_semaphore_t lock;
dispatch_once(&onceToken, ^{
cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// ,
lock = dispatch_semaphore_create(1);
});
// -1
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
_YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
// +1
dispatch_semaphore_signal(lock);
if (!meta || meta->_classInfo.needUpdate) {
meta = [[_YYModelMeta alloc] initWithClass:cls];
if (meta) {
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
dispatch_semaphore_signal(lock);
}
}
return meta;
}
3.2 ModelSetWithDictionaryFunctionベースのdictionary回転モデル
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
// context
ModelSetContext *context = _context;
//context model
__unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
// dictionary
__unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
//context model( )
__unsafe_unretained id model = (__bridge id)(context->model);
while (propertyMeta) {
// set , model( ) property
if (propertyMeta->_setter) {
ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
}
// , meta , nil while
propertyMeta = propertyMeta->_next;
};
}
3.3 ModelSetWithPropertyMetaArrayFunction複雑なモード回転モデル
static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
// context
ModelSetContext *context = _context;
//
__unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
//
__unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
// set , , crash
if (!propertyMeta->_setter) return;
id value = nil;
// @{@"bookID": @[@"id", @"ID", @"book_id"]}
if (propertyMeta->_mappedToKeyArray) {
value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
}
// @{@"desc" : @"ext.desc"}
else if (propertyMeta->_mappedToKeyPath) {
value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
}
//
else {
value = [dictionary objectForKey:propertyMeta->_mappedToKey];
}
//
if (value) {
__unsafe_unretained id model = (__bridge id)(context->model);
ModelSetValueForProperty(model, value, propertyMeta);
}
}
3.4 ModelSetValueForProperty
ModelSetValueForProperty
, objc_msgSend , property
//
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);