iOS中KVO,KVC的学习记录

本文转自:http://www.2cto.com/kf/201401/274441.html

OS中KVO,KVC的学习记录

KVO

?
#import <foundation foundation.h="">
#import "BankAccount.h"
 
@interface Person : NSObject
{
    BankAccount *bankAccount;
}
 
- (void)registerAsObserver;
 
@end
 
#import "Person.h"
 
@implementation Person
 
- (void)dealloc{
    bankAccount = nil;
}
 
- (id)init{
    self = [super init];
    if (self) {
        bankAccount = [[BankAccount alloc]init];
    }
    return self;
}
 
//OpeningBalance 指向自己的指针
static void *OpeningBalance = (void *)&OpeningBalance;
- (void)registerAsObserver{
    //监听银行账号的变化过程
     
    [bankAccount addObserver:self forKeyPath:@"openingBalance" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:OpeningBalance];
    //给银行账号bankAccount 增加一个监听者 self,监听openingBalance的变化过程
    //只要openingBalance有变化,就会让self知道
    //只要有变化,只要有新的值
}
 
- (void)unregisterObserver{
    //self从bankAccount 中解除监听对象
    [bankAccount removeObserver:self forKeyPath:@"openingBalance"];
}
 
//监听回调的函数
//bankAccount 里面openingBalance 有变化了,就会调用下面的方法
//keyPath 表示之前监听的key 也就是openingBalance
//object 表示bankAccount
//change 字典 包含了新,旧的值
//context是私有变量OpeningBalance
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
     
//    [keyPath isEqualToString:@"openingBalance"]
    if (context == OpeningBalance) {
        NSString *v = [change objectForKey:NSKeyValueChangeNewKey];
        NSLog(@"v is %@",v);
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
 
@end
 
</foundation>
#import <foundation foundation.h="">
 
@interface BankAccount : NSObject
{
    float _openingBalance;
}
 
//账号余额
@property(nonatomic,assign)float openingBalance;
 
@end
 
#import "BankAccount.h"
 
@implementation BankAccount
 
@synthesize openingBalance = _openingBalance;
 
- (id)init{
    self = [super init];
    if (self) {
        [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(balanceUpdate:) userInfo:nil repeats:YES];
    }
    return self;
}
 
- (void)balanceUpdate:(id)arg
{
    float f = self.openingBalance;
     
    f += arc4random()%100;
     
//    _openingBalance = f;不能这么写
     
    //1.
    //self.openingBalance = f;
     
    //2.
    //[self setOpeningBalance:f];
     
    //3.
    //[self setValue:[NSNumber numberWithFloat:f] forKey:@"openingBalance"];
     
    //4.
    [self willChangeValueForKey:@"openingBalance"];
    _openingBalance = f;
    [self didChangeValueForKey:@"openingBalance"];
     
     
}
 
@end
</foundation>


KVC

PlayList

#import <foundation foundation.h="">
#import "PlayItem.h"
@interface PlayList : NSObject
{
    int _number;
    NSString *_name;
    //当前播放列表
    PlayItem *_currItem;
    NSMutableArray *_itemList;
}
 
@property(nonatomic, strong)NSMutableArray *itemList;
@property(nonatomic, assign)int number;
@property(nonatomic, strong)NSString *name;
@property(nonatomic, strong)PlayItem *currItem;
 
@end
</foundation>

#import "PlayList.h"
 
@implementation PlayList
 
@synthesize number = _number, name = _name,currItem = _currItem,itemList = _itemList;
 
 
- (id)init{
    self = [super init];
    if (self) {
         
        self.currItem = [[PlayItem alloc]init];
         
        self.itemList = [NSMutableArray array];
         
        for (int i = 0; i < 20; i++) {
            PlayItem *pi = [[PlayItem alloc]init];
            pi.name = [NSString stringWithFormat:@"name %d",i];
            pi.price = 100+i;
            [self.itemList addObject:pi];
        }
         
    }
     
    return self;
}
 
- (void)setValue:(id)value forUndefinedKey:(NSString *)key  {
    NSLog(@"file is %s function %@ is calling",__FILE__,NSStringFromSelector(_cmd));
}
 
- (void)dealloc{
    self.name = nil;
    self.currItem = nil;
    self.itemList = nil;
}
 
@end



PlayItem

@interface PlayItem : NSObject
{
    NSString *_name;
    float _price;
}
 
@property(nonatomic, strong)NSString *name;
@property(nonatomic, assign)float price;
 
@end
 
 
#import "PlayItem.h"
 
@implementation PlayItem
 
@synthesize price = _price;
@synthesize name = _name;
 
- (void)dealloc{
    self.name = nil;
}
 
//如果设置里面不存在的key就会触发该方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"function %@ is calling",NSStringFromSelector(_cmd) );
}
@end

?

main.m

#import <foundation foundation.h="">
#import "PlayList.h"
#import "PlayItem.h"
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
         
        PlayList *pl = [[PlayList alloc]init];
        [pl setValue:@"播放列表" forKey:@"name"];
        NSLog(@"name is %@",pl.name);
         
        id v = [pl valueForKey:@"number"];
        NSLog(@" v is %@",v);
         
        //设置pl currItem.name 字段
        [pl setValue:@"播放列表22" forKeyPath:@"currItem.name"];
         
        NSLog(@"pl.currItem.name is %@",pl.currItem.name);
         
        //设置一批key value
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"200",@"number",@"测试",@"name", nil];
        [pl setValuesForKeysWithDictionary:dict];
        NSLog(@"name is %@ number is %d",pl.name,pl.number);
         
        //pl对象里没有test这个key,所以系统崩溃
        [pl setValue:@"hello" forKey:@"test"];
         
        id obj = [pl valueForKey:@"itemList"];
        NSLog(@"obj is %@",obj);
         
        id obj2 = [pl valueForKeyPath:@"itemList.name"];
        NSLog(@"obj name is %@",obj2);
         
//        NSLog(@"%@",pl.itemList.) 用点语法无法取到更深的值
         
        //求和,平均值,最大值,最小值
        NSLog(@"itemlist price sum is %@",[pl.itemList valueForKeyPath:@"@sum.price"]);
        NSLog(@"itemlist price sum is %@",[pl.itemList valueForKeyPath:@"@avg.price"]);
        NSLog(@"itemlist price sum is %@",[pl.itemList valueForKeyPath:@"@max.price"]);
        NSLog(@"itemlist price sum is %@",[pl.itemList valueForKeyPath:@"@min.price"]);
         
    }
    return 0;
}
</foundation>

?
自己的理解

?
//对比
        //如果要想不用kvc的话要取值则要麻烦的多
        int sum = 0;
        for (PlayItem *item in pl.itemList){
            sum += item.price;
        }
        NSLog(@"num == %d",sum);
         
        //而kvc只需要
        NSLog(@"itemlist price sum is %@",[pl.itemList valueForKeyPath:@"@sum.price"]);
         
        //如果要想取到PlayList 里的 PlayItem 里的name 不用kvc是报错的,因为点语法无法取到更深的值
        // NSLog(@"%@",pl.itemList.) ;
         
         
        //kvc只需要
        id obj3 = [pl valueForKeyPath:@"itemList.name"];
        NSLog(@"%@",obj3);
         
        //相比较kvc使代码更加简洁有效 已读

参考文章:设计模式-KVO

如果想了解的更详细,可以参考这两篇文章:

[深入浅出Cocoa]详解键值观察(KVO)及其实现机理 http://blog.csdn.net/kesalin/article/details/8194240

(译)KVO的内部实现http://www.cocoachina.com/applenews/devnews/2014/0107/7667.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值