1.iOS用什么方式实现对一个个对象的KVO?(KVO的本质是什么?)
->利用 RunTimeAPI动态生成一个字类,并且让instance 对象的isa指针指向这个全新的字类
->当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
调用顺序
willChangeValueForKey:
父类原来的setter
didChangeValueForKey:
->内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)
使用了KVO监听的对象
中间类的部分伪代码
- 原因:NSKVONotifying_MJPerson重写底层实现,目的:隐藏动态创建的类,不让用户感知
- (Class)class {
return [MJPerson class];
}
// 伪代码 Function框架
void _NSSetIntValueForKey(){
[self willChangeValueForKey:@"age"];
[self setAge:age];
[self didChangeValueForKey:@"age"];
}
// 通知监听器
- (void)didChangeValueForKey:(NSString *)key {
[obser observeValueForKeyPath:key ofObject:self change:nil content:nil];
}
-object_getClass(self.person) 和 [self.person class];分别打印什么?为什么?
- object_getClass(self.person); -> NSKVONotifying_MJPerson
- [self.person class]; -> MJPerson[self.person class]是调用的上面伪代码重写的class方法,
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
getIsa的源码
2.如何手动触发KVO?
手动调用willChangeValueForKey:和didChangeValueForKey:
3.直接修改成员变量会触发KVO吗?
不会触发KVO,因为其并没有触发setter以及相应的方法
4.通过KVC修改属性会触发KVO吗?
-会触发KVO
-KVC在修改属性时,会调用willChangeValueForKey:和didChangeValueForKey:方法;
5.KVC的赋值和取值过程是怎样的?原理是什么?
setValue:forKey的原理图
- 首先会按照setKey、_setKey的顺序查找方法,找到方法,直接调用方法并赋值;
- 未找到方法,则调用+ (BOOL)accessInstanceVariablesDirectly;
- 若accessInstanceVariablesDirectly方法返回YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到直接赋值,找不到则抛出异常;
- 若accessInstanceVariablesDirectly方法返回NO,则直接抛出异常;
(accessInstanceVariablesDirectly 返回yes代表可以访问成员变量)
valueForKey:的原理
- 首先会按照getKey、key、isKey、_key的顺序查找方法,找到直接调用取值
- 若未找到,则查看+ (BOOL)accessInstanceVariablesDirectly的返回值,若返回NO,则直接抛出异常;
- 若返回的YES,则按照_key、_isKey、key、isKey的顺序查找成员变量,找到则取值;
- 找不到则抛出异常;
6.KVC使用场景
-单层字典模型转化 [self.model setValuesForKeysWithDictionary:dict];
-通过KVC修改未暴露的属性
UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = [UIColor redColor];-使用valueForKeyPath可以获取数组中国的最大值,最小值,平均值,求和
CGFloat sum = [[list valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[list valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max = [[list valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min = [[list valueForKeyPath:@"@min.floatValue"] floatValue];-数组内部去重(@distinctUnionOfObjects.self)
NSArray *array = [list valueForKeyPath:@"@distinctUnionOfObjects.self"];
-数组合并(去重合并:distinctUnionOfArrays.self、直接合并:unionOfArrays.self)
NSArray *temp1 = @[@3, @2, @2, @1];
NSArray *temp2 = @[@3, @4, @5];
NSArray *unionArr = [@[temp1,temp2] valueForKeyPath:@"@distinctUnionOfArrays.self"];//去重合并
NSArray *unionAll = [@[temp1,temp2] valueForKeyPath:@"@unionOfArrays.self"];//直接合并-大小写转换(uppercaseString,lowercaseString)
NSArray *array = @[@"name", @"w", @"aa", @"jimsa"];
NSArray *arrayUpper = [array valueForKeyPath:@"uppercaseString"];
NSArray *arrayLower = [arrayUpper valueForKeyPath:@"lowercaseString"];
-----------------------------------end--------------------------------------













网友评论