iOS中KVO,KVC的学习记录

iOS中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


#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

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


#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;
}

自己的理解


//对比
        //如果要想不用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)及其实现机理 (译)KVO的内部实现

你可能感兴趣的:(ios,KVO,KVC)