KVC&KVO

  
25th,October,2015  JolieYang
基于Smalltalk设计, 有很多类似于Ruby、Python的动态特性,例如动态类型、动态加载、动态绑定等.


KVC(Key-Value-Code) 键值编码

对属性的动态读写,提供了一种在运行时而非编译时动态访问对象属性与成员变量的方式(运行时确定属性的绑定),从而得到更灵活和易于重用的对象. 

优缺点

优点: 灵活性;易重用
缺点: 丢失了 编译时检查(不能对属性进行编译时检查);暴力的去get/set类的私有属性, 破坏类的封装性.
对象需要用 特定的方式命名方法.这种命名约定就称为键值编码.

命名规则:

动态设置属性 1.setA方法; 2. 成员变量_a;  3.成员变量a; 4.  这个类的setValue:forUndefinedKey
动态读取属性 1.a 方法(属性a的setter方法); 2.成员变量_a; 3. 成员变量a;4.valueforUndefinedKey:方法;
valueForKey 总是返回一个id对象,非对象的返回值会自动用NSValue或NSNumber封装.不能把非对象传给setValue:forKey:

Demo:

[cell setValue:@"intValue" forKey:@"property"];
[self  valueForKeyPath:@"department.name"];
keyPath版本更灵活,key版本速度稍快.

最佳实践

valueForKeyPath为调用者提供最大的灵活性;硬编码则使用valueForKey.

     默认情况下KVC方法能够直接访问类的私有成员变量,如果我们不想这样,可以重写accessInstanceVariablesDirectly方法,并令其返回NO(默认是返回YES)。

高级技术

高阶消息传递 与 容器类操作符
高阶消息传递: NSArray *array = @[@"foo", @"bar", @"baz"];
                        NSArray *capitals = [array valueForKey:@"capitalizedString"];
备注:对于数组NSArray、集合NSSet,调用valueForKey:会对每个数组和集合成员调用valueForKey:,并返回新的数组或者集合。
容器类操作符:
              NSArray *array = @[@"foo", @"bar", @"baz"];
              NSUInteger totalLength = [[array valueForKeyPath:@"@sum.length"] intValue];
     @sum是一个操作符,对指定的属性(length)求和.


KVO(Key-Value-Observing)键值观察 

监听property的变化 通知某些对象(观察者)关于其他对象属性值发生变化的一种机制.

优缺点

优点: 性能好[开销相对于NSNotification和委托更小(只用存取方法来修改实例变量,不需要额外成本)];
          容易实现视图组件和数据模型的分离,模型类的简洁;
缺点:回调方法中传递的代表变化的字典,用起来繁琐;bug难解决(会制造出人意料的代码执行路径,有一些代码运行但没有任何可见的代码说明行为发生的原因);

DEMO:

[self.object  addObserver:self forKeyPath:self.property options:0 context:(void *)self];// 添加监听对象(注册指定key路径的监听器)
[self.object  removeObserver:self forKeyPath: self.property];// 移除监听对象(删除指定keyPath的监听器)
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context // 回调监听

最佳实践

尽量保守,简单的使用KVO; 在存在复杂相互依赖关系或者复杂的类继承层次的地方避免使用.
add on 9th,August,2016

注册键值依赖

// from AFNetworking
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
        return [NSSet setWithObject:@"networkReachabilityStatus"];
    }


    return [super keyPathsForValuesAffectingValueForKey:key];
}


+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"fullName"]) {
        NSArray *affectingKeys = @[@"lastName", @"firstName"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

参考资料:

  <<iOS编程实战>> 第22章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值