kvo /kvc

来源:互联网 发布:广东进出口数据 编辑:程序博客网 时间:2024/05/21 09:30
}
- (void)viewDidLoa
{
    [super viewDidLoad];
    //[self kvcAppModel];
    //[self kvcStudentModel];
    //[self kvcDict];
    [self kvo];
}
#pragma mark - KVO
- (void)kvo {
    _person = [[Person alloc] init];
    NSArray *arr = @[@"setter方法修改_age",@"kvc修改_age值",@"其他直接修改变量_age"];
    for ( NSInteger i = 0; i < arr.count; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        button.frame = CGRectMake(10, 100+40*i, 300, 30);
        [button setTitle:arr[i] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        button.tag = 101+i;
        [self.view addSubview:button];
    }
    //给_person指向的对象 增加一个键值观察者
    /**
     监听 _person指向的对象 指定属性有没有  用kvc 或者 setter 修改
     第一个参数就是观察者对象地址
       2  监听的属性路径
       3  监听新值和旧值 NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
       4  NULL
     */
    
    [_person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
}
#pragma mark - kvo监听到修改时那么观察者会调用
/**
 *  kvo监听到修改(kvc修改/setter修改)时那么观察者会调用
 *
 *  @param keyPath 属性路径
 *  @param object  被监听的对象 _person指向的对象
 *  @param change  变化内容(new/old)
 *  @param context 增加观察时传入的
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"kvo监听到了");
    if ([object isKindOfClass:[Person class]]) {
        //判断被监听的对象
        if ([keyPath isEqualToString:@"age"]) {
            //判断被监听对象的指定属性
            NSLog(@"_age被kvc/setter修改了");
            NSLog(@"old_age:%@",change[@"old"]);
            NSLog(@"old_age:%@",change[@"new"]);
            //NSLog(@"dict:%@",change);
            //或者
            NSLog(@"old_age:%@",change[NSKeyValueChangeOldKey]);
            NSLog(@"old_age:%@",change[NSKeyValueChangeNewKey]);
        }
    }
}
- (void)btnClick:(UIButton *)button {
    switch (button.tag) {
        case 101://setter
        {
            _person.age = 30;
        }
            break;
        case 102://kvc赋值
        {
            [_person setValue:@(25) forKeyPath:@"age"];
        }
            break;
        case 103://其他
        {
            [_person changeAge];
        }
            break;
            
        default:
            break;
    }
}
//self.name = @"xiaohong";  _name = @"xiaohong";

#pragma mark - 常见kvc
- (void)kvcDict {
    //把 一个对象的属性名 和 属性值 放入一个字典 利用kvc 赋值
    NSDictionary *dict = @{@"price":@(1.23),@"name":@"内涵"};
    
    AppModel *model = [[AppModel alloc] init];
    //kvc  同时对 多个属性赋值
    [model setValuesForKeysWithDictionary:dict];
    NSLog(@"name:%@",[model valueForKeyPath:@"name"]);
    [model release];
}

- (void)kvcStudentModel {
    //kvc 对StudentModel的属性进行赋值
    StudentModel *stu = [[StudentModel alloc] init];
    [stu setValue:@"xiaohong" forKeyPath:@"name"];
    
    AppModel *app = [[AppModel alloc] init];
    
#if 0
    [app setValue:@(1.23) forKeyPath:@"price"];
    [app setValue:@"内涵" forKeyPath:@"name"];
    
    //kvc  对_appModel赋值
    [stu setValue:app forKeyPath: @"appModel"];
#else
    //使用 keyPath 属性路径赋值
    [stu setValue:app forKeyPath:@"appModel"];
    //对属性的属性赋值
    [stu setValue:@(1.23) forKeyPath:@"appModel.price"];
    [stu setValue:@"内涵" forKeyPath:@"appModel.name"];
#endif
    
    NSLog(@"appName:%@",[app valueForKeyPath:@"name"]);
    [app release];
    
    NSLog(@"name:%@",[stu valueForKeyPath:@"name"]);//kvc 获取值
    NSLog(@"app:%@",[stu valueForKeyPath:@"appModel"]);//kvc 获取值
    [stu release];
    
}
-(void)kvcAppModel {
    AppModel *model = [[AppModel alloc] init];
    
    //1.使用kvc进行赋值 对model 的两个成员变量赋值
    //key 属性
    //value 就是属性的值
    [model setValue:@(12.1) forKey:@"price"];
    [model setValue:@"内涵段子" forKey:@"name"];

    NSLog(@"%f",[model testFunc]);//12.1
    NSLog(@"%@",[model testFunc2]);//内涵段子
    
    //2.通过属性路径 keyPath 对属性赋值
    
    [model setValue:@(121.0) forKeyPath:@"price"];
    [model setValue:@"内涵" forKeyPath:@"name"];
    /*
     kvc 赋值的原理
     运行时
     会根据 提供的key/keyPath @"price" 会去当前model指向对象的类找 有没有- setPrice:方法(如果有那么就直接调用) 如果没有那么 就会去model执行的对象类中找没有成员变量(属性)price(如果有那么就直接对price赋值)如果没有那么继续找有没有_price 成员变量,如果有那么直接对_price赋值 ,如果没有那么直接崩溃
     
     //如果要防止 崩溃  那么实现
     - setValue:forUndefinedKey:
     */
    
    NSLog(@"%f",[model testFunc]);//12.1
    NSLog(@"%@",[model testFunc2]);//内涵段子
    [model setValue:@"xiaohong" forKeyPath:@"xxx"];
    
    //kvc 还可以 获取值
    /*获取值原理
     运行时
     valueForKeyPath:
     首先 会找 model 所属的类有没有 getter方法- (NSString*)name;
     如果有那么直接调用,如果没有会找有没有成员变量name 如果有那么直接返回name的值,如果没有那么就找有没有成员变量_name,如果有那么直接返回_name的值 如果没有程序崩溃。除非实现下面的方法
       - valueForUndefinedKey:
     */
 
    NSString *name = [model valueForKeyPath:@"name"];
    NSLog(@"name:%@",name);
    [model valueForKeyPath:@"yyy"];
    
    [model release];
}
0 0
原创粉丝点击