YYModel 源码解读之NSObject+YYModel.h
Posted 马在路上
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了YYModel 源码解读之NSObject+YYModel.h相关的知识,希望对你有一定的参考价值。
本篇主要介绍的是 在真正转之前的几个辅助函数
/** Get number from property. @discussion Caller should hold strong reference to the parameters before this function returns. @param model Should not be nil. @param meta Should not be nil, meta.isCNumber should be YES, meta.getter should not be nil. @return A number object, or nil if failed. */ static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model, __unsafe_unretained _YYModelPropertyMeta *meta) { switch (meta->_type & YYEncodingTypeMask) { case YYEncodingTypeBool: { return @(((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeInt8: { return @(((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeUInt8: { return @(((uint8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeInt16: { return @(((int16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeUInt16: { return @(((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeInt32: { return @(((int32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeUInt32: { return @(((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeInt64: { return @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeUInt64: { return @(((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)); } case YYEncodingTypeFloat: { float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter); if (isnan(num) || isinf(num)) return nil; return @(num); } case YYEncodingTypeDouble: { double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter); if (isnan(num) || isinf(num)) return nil; return @(num); } case YYEncodingTypeLongDouble: { double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter); if (isnan(num) || isinf(num)) return nil; return @(num); } default: return nil; } }
这个函数的目的 是 把 _YYModelPropertyMeta.isCNumber == YES 的情况转成NSNumber
// 像这样的类型是C 的 需要调用上边的函数进行转换
@property (nonatomic, assign) int32_t blockWord;
((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)
这个方法 是 类似[obj method]; 这中方法调用的Runtime 内部实现 根据方法的返回值不同获取不同的返回类型
((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter)
下边这个方法是 把 NSNumber 赋值给 原有c 属性
/** Set number to property. @discussion Caller should hold strong reference to the parameters before this function returns. @param model Should not be nil. @param num Can be nil. @param meta Should not be nil, meta.isCNumber should be YES, meta.setter should not be nil. */ static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model, __unsafe_unretained NSNumber *num, __unsafe_unretained _YYModelPropertyMeta *meta) { switch (meta->_type & YYEncodingTypeMask) { case YYEncodingTypeBool: { ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue); } break; case YYEncodingTypeInt8: { ((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue); } break; case YYEncodingTypeUInt8: { ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue); } break; case YYEncodingTypeInt16: { ((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue); } break; case YYEncodingTypeUInt16: { ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue); } break; case YYEncodingTypeInt32: { ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue); } case YYEncodingTypeUInt32: { ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue); } break; case YYEncodingTypeInt64: { if ([num isKindOfClass:[NSDecimalNumber class]]) { ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue); } else { ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue); } } break; case YYEncodingTypeUInt64: { if ([num isKindOfClass:[NSDecimalNumber class]]) { ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue); } else { ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue); } } break; case YYEncodingTypeFloat: { float f = num.floatValue; if (isnan(f) || isinf(f)) f = 0; ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f); } break; case YYEncodingTypeDouble: { double d = num.doubleValue; if (isnan(d) || isinf(d)) d = 0; ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d); } break; case YYEncodingTypeLongDouble: { long double d = num.doubleValue; if (isnan(d) || isinf(d)) d = 0; ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d); } // break; commented for code coverage in next line default: break; } }
// 这个相对于上边的那个Runtime 方法 多了一个参数
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
((void (*)(id, SEL, 参数))(void *) objc_msgSend)((id)model, meta->_setter, 参数值);
下边的这个方法是核心方法, 把值 赋值给model 需要的参数 有3 个
1. 需要被复制的Model
2. 值
3. 需要把值赋值给谁
数据类型主要分三种情况,根据 _PropertyMeta对象
记录的类型
- propertyMeta->
_isCNumber
,基本数值类型- bool
- int8/uint8
- int16/uint16
- int32/uint32
- int64/uint64
- float
- double
- long double
- propertyMeta->
_foundationType
,Foundation Class- NSString
- NSArray
- NSSet
- NSDictionary
- NSNumber
- NSDecimalNumber
- NSValue
- NSData
- NSDate
- NSURL
- propertyMeta->
_encodingType & XZHEncodingTypeIvarMask
,属性变量类型其他类型- 自定义NSObject实体类
- Class
- SEL
- Block
- Struct/Union
- c数组
- c字符串
- c指针
以上是关于YYModel 源码解读之NSObject+YYModel.h的主要内容,如果未能解决你的问题,请参考以下文章