本篇文章主要介绍 _YYModelPropertyMeta 前边的内容
首先先解释一下前边的辅助函数和枚举变量,在写一个功能的时候,这些辅助的东西可能不是一开始就能想出来的,应该是在后续的编码过程中 逐步添加的。
#define force_inline __inline__ __attribute__((always_inline))
这行代码用到了C语言的内联函数
内联函数: 是用inline修饰的函数,内联函数在代码层次看和普通的函数结构一样,却不具备函数的性质,内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入到调用处,和宏很类似,但是有一下不同点
我们先定义一个宏
#define TABLE_COMP(x) ((x)>0?(x):0)
那么我们为什么要使用宏呢?而不是直接调用函数呢?
应为函数的调用需要把当前程序的执行循序切换到函数在内存中的地址,将函数内的程序执行完毕后,再次跳回之前调用函数的地方,这就需要记录函数调用前和调用后的状态,因此函数调用就产生了时间和空间上的开销,会影响效率,而宏只是在预编译的地方把代码展开,不需要时间和空间上的开销,效率比函数高
但是宏也有不尽如人意的地方
1. 宏不能方位对象的私有成员
2. 宏的定义很容易产生二义性
举例说明:
#define TABLE_MULTI(x) (x*x)
TABLE_MULTI(10) ------ > 结果是 100 这个是我们想要的结果
TABLE_MULTI(10+10) --------> 结果是 120 这个不是我们想要的结果 实际上 10 + 10 * 10 + 10 --> 120
为了避免这些错误,我们在使用宏的时候,应该尽量写成这样
#define TABLE_MULTI(x) ((x)*(x))
但仍然存在问题,
TABLE_MULTI(a++)
当a = 4 的时候,展开后是(4++)*(4++) == 16 并不是我们想要的结果 5*5 = 25
事实上,我们完全可以使用内联函数取代宏,他们之间的区别在于: 宏是由预处理器进行替代的,而内联函数则是通过编译器控制实现的,内联函数是真正的函数,只有在需要用到的时候才会像宏那样的展开,所以取消了函数的参数压栈,减少了调用的开销,我们可以像调用函数一样调用内联函数,而不必担心产生于处理宏一样的问题。
好了,内联函数相信大家应该已经明白怎么使用了,接下来,我们看源码
/// Foundation Class Type
typedef NS_ENUM (NSUInteger, YYEncodingNSType) {
YYEncodingTypeNSUnknown = ,
YYEncodingTypeNSString,
YYEncodingTypeNSMutableString,
YYEncodingTypeNSValue,
YYEncodingTypeNSNumber,
YYEncodingTypeNSDecimalNumber, /// 科学计数值 当值很大的时候使用,比如: 310000000 ---> 3.1 * 10的8次方
YYEncodingTypeNSData,
YYEncodingTypeNSMutableData,
YYEncodingTypeNSDate,
YYEncodingTypeNSURL,
YYEncodingTypeNSArray,
YYEncodingTypeNSMutableArray,
YYEncodingTypeNSDictionary,
YYEncodingTypeNSMutableDictionary,
YYEncodingTypeNSSet,
YYEncodingTypeNSMutableSet,
};
这个是Foundation Class 的类型封装,基本上都是我们熟悉的 NSDecimaNumber 是科学计数值的类型,往往 定义了一个枚举后,应该提供一个方法来进行必要的转换
/// Get the Foundation class type from property info.
static force_inline YYEncodingNSType YYClassGetNSType(Class cls) {
if (!cls) return YYEncodingTypeNSUnknown;
if ([cls isSubclassOfClass:[NSMutableString class]]) return YYEncodingTypeNSMutableString;
if ([cls isSubclassOfClass:[NSString class]]) return YYEncodingTypeNSString;
if ([cls isSubclassOfClass:[NSDecimalNumber class]]) return YYEncodingTypeNSDecimalNumber;
if ([cls isSubclassOfClass:[NSNumber class]]) return YYEncodingTypeNSNumber;
if ([cls isSubclassOfClass:[NSValue class]]) return YYEncodingTypeNSValue;
if ([cls isSubclassOfClass:[NSMutableData class]]) return YYEncodingTypeNSMutableData;
if ([cls isSubclassOfClass:[NSData class]]) return YYEncodingTypeNSData;
if ([cls isSubclassOfClass:[NSDate class]]) return YYEncodingTypeNSDate;
if ([cls isSubclassOfClass:[NSURL class]]) return YYEncodingTypeNSURL;
if ([cls isSubclassOfClass:[NSMutableArray class]]) return YYEncodingTypeNSMutableArray;
if ([cls isSubclassOfClass:[NSArray class]]) return YYEncodingTypeNSArray;
if ([cls isSubclassOfClass:[NSMutableDictionary class]]) return YYEncodingTypeNSMutableDictionary;
if ([cls isSubclassOfClass:[NSDictionary class]]) return YYEncodingTypeNSDictionary;
if ([cls isSubclassOfClass:[NSMutableSet class]]) return YYEncodingTypeNSMutableSet;
if ([cls isSubclassOfClass:[NSSet class]]) return YYEncodingTypeNSSet;
return YYEncodingTypeNSUnknown;
}
判断是否是一个C 的类型
/// Whether the type is c number.
static force_inline BOOL YYEncodingTypeIsCNumber(YYEncodingType type) {
switch (type & YYEncodingTypeMask) {
case YYEncodingTypeBool:
case YYEncodingTypeInt8:
case YYEncodingTypeUInt8:
case YYEncodingTypeInt16:
case YYEncodingTypeUInt16:
case YYEncodingTypeInt32:
case YYEncodingTypeUInt32:
case YYEncodingTypeInt64:
case YYEncodingTypeUInt64:
case YYEncodingTypeFloat:
case YYEncodingTypeDouble:
case YYEncodingTypeLongDouble: return YES;
default: return NO;
}
}
接下来的方法是 在id 类型中 解析 NSNumber , 这里用到了NSCharacterSet 这个类,下边对这个类做一些简单介绍
这个类配合NSScanner 做字符串的过滤操作
/// Parse a number value from 'id'.
static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value) {
static NSCharacterSet *dot;
static NSDictionary *dic;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', )];
dic = @{@"TRUE" : @(YES),
@"True" : @(YES),
@"true" : @(YES),
@"FALSE" : @(NO),
@"False" : @(NO),
@"false" : @(NO),
@"YES" : @(YES),
@"Yes" : @(YES),
@"yes" : @(YES),
@"NO" : @(NO),
@"No" : @(NO),
@"no" : @(NO),
@"NIL" : (id)kCFNull,
@"Nil" : (id)kCFNull,
@"nil" : (id)kCFNull,
@"NULL" : (id)kCFNull,
@"Null" : (id)kCFNull,
@"null" : (id)kCFNull,
@"(NULL)" : (id)kCFNull,
@"(Null)" : (id)kCFNull,
@"(null)" : (id)kCFNull,
@"<NULL>" : (id)kCFNull,
@"<Null>" : (id)kCFNull,
@"<null>" : (id)kCFNull};
}); // 判空
if (!value || value == (id)kCFNull) return nil;
// 如果是NSNumber 直接返回
if ([value isKindOfClass:[NSNumber class]]) return value;
// 如果是字符串
if ([value isKindOfClass:[NSString class]]) { // 取出字典中映射的值
NSNumber *num = dic[value];
if (num) {
if (num == (id)kCFNull) return nil;
return num;
} // 字符串中包含字符‘.’
if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
const char *cstring = ((NSString *)value).UTF8String;
if (!cstring) return nil; // 把字符串转换成浮点数
double num = atof(cstring);
if (isnan(num) || isinf(num)) return nil;
return @(num);
} else {
const char *cstring = ((NSString *)value).UTF8String;
if (!cstring) return nil; // 返回字符串 的 长长整型
return @(atoll(cstring));
}
} return nil;
}
上边代码的主要功能就是把id 类型 转换成NSNumber 类型,其中有两个函数
atof() ---- 将字符串转换成浮点类型
atoll() ---- 将字符串转换成长长整型
下边这个方法就是把字符串转换成日期的方法
使用Block来保存 可支持的字符串和转换结果,,然后根据字符串的长度进行转换
/// Parse string to date.
static force_inline NSDate *YYNSDateFromString(__unsafe_unretained NSString *string) {
typedef NSDate* (^YYNSDateParseBlock)(NSString *string);
#define kParserNum 34
static YYNSDateParseBlock blocks[kParserNum + ] = {};
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
{
/*
2014-01-20 // Google
*/
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:];
formatter.dateFormat = @"yyyy-MM-dd";
blocks[] = ^(NSString *string) { return [formatter dateFromString:string]; };
} {
/*
2014-01-20 12:24:48
2014-01-20T12:24:48 // Google
2014-01-20 12:24:48.000
2014-01-20T12:24:48.000
*/
NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
formatter1.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter1.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:];
formatter1.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss"; NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter2.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:];
formatter2.dateFormat = @"yyyy-MM-dd HH:mm:ss"; NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
formatter3.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter3.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:];
formatter3.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS"; NSDateFormatter *formatter4 = [[NSDateFormatter alloc] init];
formatter4.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter4.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:];
formatter4.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; blocks[] = ^(NSString *string) {
if ([string characterAtIndex:] == 'T') {
return [formatter1 dateFromString:string];
} else {
return [formatter2 dateFromString:string];
}
}; blocks[] = ^(NSString *string) {
if ([string characterAtIndex:] == 'T') {
return [formatter3 dateFromString:string];
} else {
return [formatter4 dateFromString:string];
}
};
} {
/*
2014-01-20T12:24:48Z // Github, Apple
2014-01-20T12:24:48+0800 // Facebook
2014-01-20T12:24:48+12:00 // Google
2014-01-20T12:24:48.000Z
2014-01-20T12:24:48.000+0800
2014-01-20T12:24:48.000+12:00
*/
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ"; NSDateFormatter *formatter2 = [NSDateFormatter new];
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; blocks[] = ^(NSString *string) { return [formatter dateFromString:string]; };
blocks[] = ^(NSString *string) { return [formatter dateFromString:string]?: [formatter2 dateFromString:string]; };
blocks[] = ^(NSString *string) { return [formatter dateFromString:string]; };
blocks[] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
blocks[] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
} {
/*
Fri Sep 04 00:12:21 +0800 2015 // Weibo, Twitter
Fri Sep 04 00:12:21.000 +0800 2015
*/
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; NSDateFormatter *formatter2 = [NSDateFormatter new];
formatter2.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter2.dateFormat = @"EEE MMM dd HH:mm:ss.SSS Z yyyy"; blocks[] = ^(NSString *string) { return [formatter dateFromString:string]; };
blocks[] = ^(NSString *string) { return [formatter2 dateFromString:string]; };
}
});
if (!string) return nil;
if (string.length > kParserNum) return nil;
YYNSDateParseBlock parser = blocks[string.length];
if (!parser) return nil;
return parser(string);
#undef kParserNum
}
获得NSBlock 这个类 ,
/// Get the 'NSBlock' class.
static force_inline Class YYNSBlockClass() {
static Class cls;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
void (^block)(void) = ^{};
cls = ((NSObject *)block).class;
while (class_getSuperclass(cls) != [NSObject class]) {
NSLog(@"cls = %@",class_getSuperclass(cls));
cls = class_getSuperclass(cls);
}
});
return cls; // current is "NSBlock"
}
加入了打印我们可以看出 block 的父类的关系是
block -------> NSGlobalBlock ---------> NSBlock
获取标准的时间的格式
/**
Get the ISO date formatter. ISO8601 format example:
2010-07-09T16:13:30+12:00
2011-01-11T11:11:11+0000
2011-01-26T19:06:43Z length: 20/24/25
*/
static force_inline NSDateFormatter *YYISODateFormatter() {
static NSDateFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
});
return formatter;
}
根据字典和key 或者keypath 获取 value
@{
@"name" : @"machao",
@"user" : @{
@"uid":@{
@"name":@"abc",
@"addrs":@"beijing",
},
@"pic" : @"http://7ke.com",
},
};
使用下边的方法的思路是获取这样的一个值
[NSDictionary valueForKeyPath:@"user.uid.name"]
数组keys 装着的是@[@"user",@"uid",@"name"];
/// Get the value with key paths from dictionary
/// The dic should be NSDictionary, and the keyPath should not be nil.
static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
id value = nil;
for (NSUInteger i = , max = keyPaths.count; i < max; i++) {
value = dic[keyPaths[i]];
if (i + < max) {
if ([value isKindOfClass:[NSDictionary class]]) {
dic = value;
} else {
return nil;
}
}
}
return value;
} /// Get the value with multi key (or key path) from dictionary
/// The dic should be NSDictionary
static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
id value = nil;
for (NSString *key in multiKeys) {
if ([key isKindOfClass:[NSString class]]) {
value = dic[key];
if (value) break;
} else {
value = YYValueForKeyPath(dic, (NSArray *)key);
if (value) break;
}
}
return value;
}
----------- 分隔线 -------------
接下来 分析_YYModelPropertyMeta 这个类 ,这个类在本文件中是一个私有类
有一个@package 需要注意一下,
@protected 该类和所有子类中的方法可以直接访问这样的变量。
@private 该类中的方法可以访问,子类不可以访问。
@public 可以被所有的类访问
@package 本包内使用,跨包不可以
/// A property info in object model.
@interface _YYModelPropertyMeta : NSObject {
@package
NSString *_name; ///< property's name
YYEncodingType _type; ///< property's type
YYEncodingNSType _nsType; ///< property's Foundation type
BOOL _isCNumber; ///< is c number type
Class _cls; ///< property's class, or nil
Class _genericCls; ///< container's generic class, or nil if threr's no generic class
SEL _getter; ///< getter, or nil if the instances cannot respond
SEL _setter; ///< setter, or nil if the instances cannot respond
BOOL _isKVCCompatible; ///< YES if it can access with key-value coding
BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver
BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary: /*
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
NSArray *_mappedToKeyPath; ///< the key path mapped to (nil if the name is not key path)
NSArray *_mappedToKeyArray; ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys)
YYClassPropertyInfo *_info; ///< property's info
_YYModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key.
}
@end
这个私有的类中包含了 一条@property 的全部信息,我们可以了解到一条@property 其实是包含很多信息的
1. _name ------> 名称
2. _type -------> @encode()编码 转换后的类型 详见 YYModel源码解读 (二) 之 YYClassInfo.h(1)
3. _nsType ------> 自定义的Foundation 类型
4. _isCNumber -------- > 类型是否是c类型
5. _cls --------> property 的类型
6. _genericCls ---------> 这个是容器的类型, 比如: NSArray NSSet NSDictionary
7. _getter -------- > getter 方法 (可能为空)
8. _setter ---------> setter 方法(可能为空)
9. _isKVCCompatible ---------- > 能否被归档,属性需要实现setter 和 getter 方法
10. _isStructAvailableForKeyedArchiver ------- > 结构体类型是否支持归档
11. _hasCustomClassFromDictionary ---------> 是否实现了 +modelCustomClassForDictionary 方法 自定义了返回类型
12. _mappedToKey --------->
接下来我们看看实现,有些信息是我们在这个参数中可以直接获取的,直接赋值就好,其他的需要判断的就判断,值得注意的是,因为本类是支持归档的 所以要知道哪些是支持归档的,哪些是不支持归档的,
支持归档的结构体:
// 32 bit
[set addObject:@"{CGSize=ff}"];
[set addObject:@"{CGPoint=ff}"];
[set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
[set addObject:@"{CGAffineTransform=ffffff}"];
[set addObject:@"{UIEdgeInsets=ffff}"];
[set addObject:@"{UIOffset=ff}"];
// 64 bit
[set addObject:@"{CGSize=dd}"];
[set addObject:@"{CGPoint=dd}"];
[set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
[set addObject:@"{CGAffineTransform=dddddd}"];
[set addObject:@"{UIEdgeInsets=dddd}"];
[set addObject:@"{UIOffset=dd}"];
不支持归档的:
long double
pointer (such as SEL/CoreFoundation object)
+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic { // 初始化信息
_YYModelPropertyMeta *meta = [self new];
meta->_name = propertyInfo.name;
meta->_type = propertyInfo.type;
meta->_info = propertyInfo;
meta->_genericCls = generic; // 如果是Foundation 类型
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeObject) {
meta->_nsType = YYClassGetNSType(propertyInfo.cls);
}
// 否则判断是不是C 类型
else {
meta->_isCNumber = YYEncodingTypeIsCNumber(meta->_type);
} // 结构体类型
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeStruct) {
/*
It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
*/
static NSSet *types = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSMutableSet *set = [NSMutableSet new];
// 32 bit
[set addObject:@"{CGSize=ff}"];
[set addObject:@"{CGPoint=ff}"];
[set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
[set addObject:@"{CGAffineTransform=ffffff}"];
[set addObject:@"{UIEdgeInsets=ffff}"];
[set addObject:@"{UIOffset=ff}"];
// 64 bit
[set addObject:@"{CGSize=dd}"];
[set addObject:@"{CGPoint=dd}"];
[set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
[set addObject:@"{CGAffineTransform=dddddd}"];
[set addObject:@"{UIEdgeInsets=dddd}"];
[set addObject:@"{UIOffset=dd}"];
types = set;
}); // 由此看来,ios的归档大概只支持上边的几种结构体类型
if ([types containsObject:propertyInfo.typeEncoding]) {
meta->_isStructAvailableForKeyedArchiver = YES;
}
} meta->_cls = propertyInfo.cls; // 判断是否实现了modelCustomClassForDictionary方法
if (generic) {
meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
} else if (meta->_cls && meta->_nsType == YYEncodingTypeNSUnknown) {
meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
} // 判断property 所属的类能否相应自身的getter 方法
if (propertyInfo.getter) {
if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
meta->_getter = propertyInfo.getter;
}
}
// 判断property 所属的类能否相应自身的setter 方法
if (propertyInfo.setter) {
if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
meta->_setter = propertyInfo.setter;
}
} // 判断能够被归档,
if (meta->_getter && meta->_setter) {
/*
KVC invalid type:
long double
pointer (such as SEL/CoreFoundation object)
*/
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeBool:
case YYEncodingTypeInt8:
case YYEncodingTypeUInt8:
case YYEncodingTypeInt16:
case YYEncodingTypeUInt16:
case YYEncodingTypeInt32:
case YYEncodingTypeUInt32:
case YYEncodingTypeInt64:
case YYEncodingTypeUInt64:
case YYEncodingTypeFloat:
case YYEncodingTypeDouble:
case YYEncodingTypeObject:
case YYEncodingTypeClass:
case YYEncodingTypeBlock:
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
meta->_isKVCCompatible = YES;
} break;
default: break;
}
} return meta;
}
YYModel 源码解读(二)之NSObject+YYModel.h (1)的更多相关文章
-
jQuery.Callbacks 源码解读二
一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...
-
(转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...
-
YYModel 源码解读(二)之YYClassInfo.h (3)
前边3篇介绍了YYClassinfo 文件的组成单元,算是功能的分割,按照业务的设计思想来说,方向应该是相反的 由此引申出我们在设计api的思想其实和项目管理是很类似的----- 一些题外话 1.目的 ...
-
YYModel 源码解读 总结
在使用swfit写代码的过程中,使用了下oc写的字典转模型,发现有些属性转不成功,就萌生了阅读源码的想法. 其实一直都知道Runtime机制,但并没有系统的学习,可能是因为平时的使用比较少,无意间在g ...
-
YYModel 源码解读(一)之YYModel.h
#if __has_include(<YYModel/YYModel.h>) FOUNDATION_EXPORT double YYModelVersionNumber; FOUNDATI ...
-
mybatis源码解读(二)——构建Configuration对象
Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...
-
ConcurrentHashMap源码解读二
接下来就讲解put里面的三个方法,分别是 1.数组初始化方法initTable() 2.线程协助扩容方法helpTransfer() 3.计数方法addCount() 首先是数组初始化,再将源码之前, ...
-
go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
nsqlookupd: 官方文档解释见:http://bitly.github.io/nsq/components/nsqlookupd.html 用官方话来讲是:nsqlookupd管理拓扑信息,客 ...
-
vue2.0 源码解读(二)
小伞最近比较忙,阅读源码的速度越来越慢了 最近和朋友交流的时候,发现他们对于源码的目录结构都不是很清楚 红色圈子内是我们需要关心的地方 compiler 模板编译部分 core 核心实现部分 ent ...
随机推荐
-
caffe问题集锦
不断更新中... 1.问题:check failure stack trace:*** 解决方法:路径错误,重新去看自己的路径是否有错误 2.Check failed: error == cudaSu ...
-
Mybatis配置中遇到的问题和问题分析
1.为什么这么配置,这个配置主要是作用是什么,主要的是针对什么 mybatis之xml映射配置 sql语句当中 Example_Where_Clause 这个仅仅是一段sql语句吗? <trim ...
-
ACM1007
题目:DNA序列排序 DNA序列由一序列的大写英文字母表示,如ABCDEF.紊乱程度表示组成DNA序列的字母按照由小到大的顺序进行排列程度,如ABC的紊乱程度比ACB小,因为它字母都是由小到大排序的. ...
-
重写方法的利器-super
重写方法的利器-super class ilist(list): def __init__(self,dft=None,r=list()): super(ilist, self).__init__(r ...
-
使用Set集合对List集合进行去重
/** * 使用Set集合对List集合进行去重 **/ public class SetTest { /** * List集合的泛型为Integer类型 * * @author hongwei.li ...
-
Android开发过程中的坑及解决方法收录(六)
1. file.listFiles 空指针异常 最近在弄个小项目,类似一个文件管理器,需要获得手机存储里的目录之后显示,但是运行过程中出现错误,搜索了资料,得出了以下的解决办法 问题产生的原因: an ...
-
android系统中如何通过程序打开某个AccessibilityService
android系统中如何通过程序打开某个AccessibilityService(系统辅助服务)? 通常的做法是注册AccessibilityService(辅助服务)后跳转到设置启动服务页面引导用户 ...
-
java连接163邮箱发送邮件
一:jar包:下载链接:链接: http://pan.baidu.com/s/1dDhIDLv 密码: ibg5二:代码 1-------------------------------------- ...
-
Ionic 2 + 手动搭建开发环境教程 【转】
ionic简介 为什么选用ionic: 彻底开源且免费 性能优异 基于红的发紫的AngularJs 漂亮的UI 强大的命令行(基于更热门的nodejs) 开发团队非常活跃. ngCordova,将主流 ...
-
分布式系统监视zabbix讲解八之自动发现/自动注册--技术流ken
自动发现(LLD) 概述 自动发现(LLD)提供了一种在计算机上为不同实体自动创建监控项,触发器和图形的方法.例如,Zabbix可以在你的机器上自动开始监控文件系统或网络接口,而无需为每个文件系统或网 ...