KVC与KVO

KVC与KVOKVC与KVO是ObjectC的关键概念,特别是初学者极易搞混,下面是个人的学习总结!KVC,即是指NSKeyValueCoding,KVC有两个方法:一个是设置key的值,另一个是获取key的值。KVO,即Key-ValueObserving建立在KVC之上,它能够观察一个对象的KVCkeypath值的变化。

KVC与KVO纠缠不清的关系

KVC 与 KVO 是 Objective C 的关键概念,很多初学者特别容易被搞混了,个人认为必须理解的东西,下面是实例讲解。

Key-Value Coding (KVC)

一,概述

KVC是KeyValueCoding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。

一个对象拥有某些属性。比如说,一个 Person 对象有一个 name 和一个 address 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 name 和 address 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:一个是设置 key 的值,另一个是获取 key 的值。如下面三的例子:(另外同KVO一样Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。)

二,使用方法

关键方法定义在:

  NSKeyValueCodingprotocol
KVC支持类对象和内建基本数据类型。
获取值
    valueForKey:,传入NSString属性的名字。
    valueForKeyPath:,传入NSString属性的路径,xx.xx形式。
    valueForUndefinedKey它的默认实现是抛出异常,可以重写这函数做错误处理。
修改值
    setValue:forKey:
    setValue:forKeyPath:
    setValue:forUndefinedKey:
    setNilValueForKey:当对非类对象属性设置nil时,调用,默认抛出异常。
一对多关系成员的情况
    mutableArrayValueForKey:有序一对多关系成员  NSArray
    mutableSetValueForKey:无序一对多关系成员  NSSet

三,注意


  • 1.对于valueForKey:方法用于以字符串调用对象的get属性方法,或者读取成员变量的值;与之相对的是setValue:forKey:,它用于以字符串调用对象的set属性方法,或者修改成员变量的值。

  • 2.对于基本数据类型,KVC方法会对基本数据类型进行封装(基本数据类型封装为NSNumber,其他结构体类型封装为NSValue)。

  • 3.默认情况下KVC方法能够直接访问类的私有成员变量,如果我们不想这样,可以重写方法,并令其返回NO(默认是返回YES)。KVC方法定义在NSKeyValueCoding类别中,该类别附加于NSObject类上,所以所有对象都具有这些方法。

  • 4.在一些特殊的类的对象上调用KVC方法会有特别的效果。对于数组NSArray、集合NSSet,调用valueForKey:会对每个数组和集合成员调用valueForKey:,并返回新的数组或者集合。

  • 5.使用KVC的好处是非常灵活,但同时也丢失了编译时检查。

四,实例:

void changeName(Person *p, NSString *newName)

{
        NSString *originalName = [p valueForKey:@"name"];

    [p setValue:newName forKey:@"name"];

    NSLog(@"Changed %@'s name to: %@", originalName, newName);

}

现在,如果 Person 有另外一个 key 配偶(spouse),spouse 的 key 值是另一个 Person 对象,用 KVC 可以这样写:

void logMarriage(Person *p)

{
       NSString *personsName = [p valueForKey:@"name"];
        NSString *spousesName = [p valueForKeyPath:@"spouse.name"];

    NSLog(@"%@ is happily married to %@", personsName, spousesName);

}

key 与 key pat 要区分开来,key 可以从一个对象中获取值,而 key path 可以将多个 key 用点号 “.” 分割连接起来,比如:

[p valueForKeyPath:@"spouse.name"];

相当于这样……

[[p valueForKey:@"spouse"] valueForKey:@"name"];

好了,以上是 KVC 的基本知识,接着看看 KVO。

Key-Value Observing (KVO)

一,概述

Key-Value Observing (KVO) 建立在 KVC 之上,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知,它能够观察一个对象的 KVC key path 值的变化。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。

二,使用方法

系统框架已经支持KVO,所以程序员在使用的时候非常简单。

  • 1 . 注册,指定被观察者的属性(实现观察)

  • 2 . 实现回调方法(在被观察的 key path 的值变化时调用)

  • 3 . 移除观察(dealloc)

三,实例:

做一个类似于血量条的例子
1.实现观察对象

   // 设置一个Model
    _model = [[Model alloc] init];

    // 观察_model对象的volumn属性的变化
    [_model addObserver:self forKeyPath:@"volumn" options:NSKeyValueObservingOptionNew context:(__bridge void *)(_pulseView)];
}

2.操作model

// 操作model
- (void)pullAction:(UISwipeGestureRecognizer *)gesture
{
    if (gesture.direction == UISwipeGestureRecognizerDirectionUp) {
        if (self.model.volumn < 400) {
            self.model.volumn += 100;
        }else{

            UIAlertView *alertup = [[UIAlertView alloc] initWithTitle:@"警告" message:@"够了够了 ,你还想弄啥" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil];
            [alertup show];
            return ;
        }
    } else {
        if (self.model.volumn > 100) {
            self.model.volumn -= 100;
        } else {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"警告" message:@"血量严重不足!" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil];
            ;
            return;
        }
    }
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"volumn"]) {
        QYView *view = (__bridge QYView *)(context);
        CGRect frame = view.frame;
        frame.size.height = [change[NSKeyValueChangeNewKey] intValue];
        frame.origin.y = _maxY - frame.size.height;

        [UIView animateWithDuration:0.3 animations:^{
            view.frame = frame;
            view.backgroundColor = self.colors[(_model.volumn/100)-1];
        }];
    }
}

3.移除观察
增加观察与取消观察是成对出现的,所以需要在最后的时候,移除观察者

- (void)dealloc
{
    [self removeObserver:self forKeyPath:@"volumn" context:(__bridge void *)(_pulseView)];
}

4.另附操作手势,观察血量变化显示颜色

- (NSArray *)colors
{
    if (_colors == nil) {
        _colors = @[[UIColor purpleColor], [UIColor redColor], [UIColor yellowColor], [UIColor greenColor]];
    }
    return _colors;
}
- (void)viewDidLoad {
    [super viewDidLoad];
     // View
    _pulseView = [[NSBundle mainBundle] loadNibNamed:@"QYView" owner:self options:0][0];
    [self.view addSubview:_pulseView];
    _pulseView.center = self.view.center;
    _maxY = CGRectGetMaxY(_pulseView.frame);
        // 添加手势识别器
    UISwipeGestureRecognizer *pullUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(pullAction:)];
    pullUp.direction = UISwipeGestureRecognizerDirectionUp;
    [_pulseView addGestureRecognizer:pullUp];
    UISwipeGestureRecognizer *pullDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(pullAction:)];
    pullDown.direction = UISwipeGestureRecognizerDirectionDown;
    [_pulseView addGestureRecognizer:pullDown];
    }

四,小结

KVO这种编码方式使用起来很简单,很适用与”voloumn”修改后,引发的UIVIew的变化这种情况,它通过 key path 观察对象的值就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。

今天的文章KVC与KVO分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/7206.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注