kvo浅析与实例

今天做播放器的时候,使用到了KVO,去网上搜了一些相关的资料

什么是KVO?

KVO是Key-Value-Observing的缩写,通过KVO这种机制对象可以通过它得到其他对象的某个属性的变更通知。这种机制在MVC模式下显得更为重要,KVO可以让视图对象经过控制器观察模型对象的变更从而做出更新等操作。

KVO这一机制是基于NSKeyValueObserving协议的,Cocoa通过这个协议为所有遵循协议的对象提供了自动观察属性变化的能力。在NSObject中已经为我们实现了这一协议,所以我们不必去实现这个协议。

下图形象的表示了KVO的一种工作流程:

Screen Shot 2014-06-15 at 3.31.32 PM

为什么要使用KVO?

有的朋友可能会有疑问,为什么要使用KVO呢?KVO能实现的我使用Setter方法同样能实现啊。其实不然KVO存在还是有它的价值的,那么接下来我们细数一下KVO的独特价值吧:

1.我们创建一两个setter方法感觉没什么,但是如果要观察的属性非常多,那么还能一一重写setter方法来实现吗?想必大家心里已有了答案,但是利用KVO则能很好的解决上述问题。

2.我们自定义的类是很容易改写setter方法的,但是如果你是用一个已经编译好了的类库时要监控其中一个属性时怎么办?难道还要去重写setter方法?如果使用KVO则很轻松解决问题。

3.使用KVO能够方便的记录变化前的值和变化后的值,不适用KVO你还要自己来解决这些问题。

4.KVO让你的代码看起来更加简洁清晰易于维护。

如何使用KVO呢?

首先,你要为你想观察的对象添加一个观察者代码如下:

[object addObserver: observer forKeyPath: @"frame" options: 0 context: nil];

 

调用方法是:

object : 被观察对象

observer: 观察对象

forKeyPath里面带上property的name,如UIView的frame、center等等

options: 有4个值,分别是:

NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法

NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法

NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。

NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。

注:例子里的0就代表不带任何参数进去

context: 可以带入一些参数,任何类型都可以,强制转就可以。

接下来观察到值的变化后该应该调用相关的方法来处理,这个方法是:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

其中:

keyPath: 对应forKeyPath

  object:  被观察的对象

  change:  对应options里的NSKeyValueObservingOptionNew、NSKeyValueObservingOptionOld等

  context: 对应context

实战代码

我们写一个学生类写一个pageview类来观察学生类中某些属性的变化并作出相关响应。

 

1

Student.h

2

#import <Foundation/Foundation.h>

3


4

@interface Student : NSObject

5


6

@property (nonatomic)NSString *name;

7


8

@property (nonatomic)NSString *courseName;

9


10

@property (nonatomic)double age;

11


12

- (void)changeCourseName:(NSString *)newCourseName;

13


14

@end

15


16

Student.m

17

#import "Student.h"

18


19

@implementation Student

20


21

- (void)changeCourseName:(NSString *)newCourseName{

22

    _courseName = newCourseName;

23

}

24


25

@end

26


27

pageView.h

28

#import <Foundation/Foundation.h>

29

#import "Student.h"

30


31

@interface pageView : NSObject

32

- (id)init:(Student*)stu;

33

@end

34


35

pageView.m

36

#import "pageView.h"

37


38

@implementation pageView{

39

    Student *student;

40

}

41


42

- (id)init:(Student*)stu{

43

    if(self = [super init]){

44

        student = stu;

45

        [stu addObserver:self

46

              forKeyPath:@"courseName"

47

                 options:NSKeyValueObservingOptionNew

48

         |NSKeyValueObservingOptionOld

49

                 context:nil];

50

        [stu addObserver:self

51

              forKeyPath:@"age"

52

                 options:NSKeyValueObservingOptionNew

53

         |NSKeyValueObservingOptionOld

54

                 context:nil];

55

    }

56

    return self;

57

}

58


59

- (void)dealloc{

60

    [student removeObserver:self forKeyPath:@"courseName"];

61

}

62


63

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

64

    if([keyPath isEqualToString:@"courseName"]){

65

        NSLog(@"课程发生了改变");

66

        NSLog(@"新课程是:%@  老课程是:%@",[change objectForKey:@"new"],[change objectForKey:@"old"]);

67

    }else if([keyPath isEqualToString:@"age"]){

68

        NSLog(@"课程发生了改变");

69

        NSLog(@"新课程是:%@  老课程是:%@",[change objectForKey:@"new"],[change objectForKey:@"old"]);

70

    }

71

}

72


73

@end

74


75

main.m

76

#import <Foundation/Foundation.h>

77

#import "Student.h"

78

#import "pageView.h"

79


80

int main(int argc, const char * argv[])

81

{

82


83

    @autoreleasepool {

84


85

        Student *student = [[Student alloc] init];

86

        student.courseName = @"math";

87

        student.age = 10;

88

        pageView *view = [[pageView alloc] init:student];

89

        student.courseName = @"ddd";

90

        student.age = 15;

91

        NSLog(@"%@",student.courseName);

92


93

    }

94

    return 0;

95

}

当我们观察的那个值与多个其他的值有关时我们应该重写

+ (NSSet *)keyPathsForValuesAffecting<key>方法

其中<key>是你要监听的那个值的名字如rect

+ (NSSet *)keyPathsForValuesAffectingRect

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值