KVO 实战解析


前人已经说的很清楚了!我也没必要在重复了!我也没人家总结的好!


通过一个遛狗例子来解析KVO  

下面介绍来自 

http://www.cppblog.com/kesalin/archive/2012/11/17/kvo.html   总结的很全面 值得研究

一,前言

Objective-C 中的键(key)-值(value)观察(KVO)并不是什么新鲜事物,它来源于设计模式中的观察者模式,其基本思想就是:

一个目标对象管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。这个主动通知通常是通过调用各观察者对象所提供的接口方法来实现的。观察者模式较完美地将目标对象与观察者对象解耦。

在 Objective-C 中有两种使用键值观察的方式:手动或自动,此外还支持注册依赖键(即一个键依赖于其他键,其他键的变化也会作用到该键)。下面将一一讲述这些,并会深入 Objective-C 内部一窥键值观察是如何实现的。


二,运用键值观察

1,注册与解除注册

如果我们已经有了包含可供键值观察属性的类,那么就可以通过在该类的对象(被观察对象)上调用名为 NSKeyValueObserverRegistration 的 category 方法将观察者对象与被观察者对象注册与解除注册:

  
  
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

这两个方法的定义在 Foundation/NSKeyValueObserving.h 中,NSObject,NSArray,NSSet均实现了以上方法,因此我们不仅可以观察普通对象,还可以观察数组或结合类对象。在该头文件中,我们还可以看到 NSObject 还实现了 NSKeyValueObserverNotification 的 category 方法(更多类似方法,请查看该头文件):

  
  
- (void)willChangeValueForKey:(NSString *)key; - (void)didChangeValueForKey:(NSString *)key;

这两个方法在手动实现键值观察时会用到,暂且不提。

值得注意的是:不要忘记解除注册,否则会导致资源泄露。

2,设置属性

将观察者与被观察者注册好之后,就可以对观察者对象的属性进行操作,这些变更操作就会被通知给观察者对象。注意,只有遵循 KVO 方式来设置属性,观察者对象才会获取通知,也就是说遵循使用属性的 setter 方法,或通过 key-path 来设置:

  
  
[target setAge:30];  [target setValue:[NSNumber numberWithInt:30] forKey:@"age"];
3,处理变更通知

观察者需要实现名为 NSKeyValueObserving 的 category 方法来处理收到的变更通知:

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

在这里,change 这个字典保存了变更信息,具体是哪些信息取决于注册时的 NSKeyValueObservingOptions。


我先创建了一个 dogName 的函数作为被观察的对象

dogName.h 文件 邪恶的下划线/


#import <Foundation/Foundation.h>


@interface dogName :NSObject

{

    NSString *dongNameString;

}

@property (strong,nonatomic)NSString *dongNameString;

@end


dogName.m 文件 邪恶的下划线/

#import "dogName.h"


@implementation dogName

@synthesize dongNameString;

-(id)init

{

    if (self = [superinit])

    {

  

       //初始化了一条狗 这条狗看家

        dongNameString = [self   setDogName:@"大黄"];

       //6秒后 名叫小花的狗来接替大黄这条狗看家  

        [NSTimerscheduledTimerWithTimeInterval:6target:selfselector:@selector(changeName)userInfo:nilrepeats:NO];

        

        

    }

    returnself;

}


-(void)changeName

{

    

  [selfsetValue:[self   setDogName:@"大黄走了小花来了"] forKey:@"dongNameString"];

    

}


-(NSString *)setDogName:(NSString *)name

{

             return name;

}


//自动通知  大黄走了小花来了一定要告诉主人来 谁在看家 

+ (BOOL) automaticallyNotifiesObserversForKey:(NSString*)key

{

// 对于名为dongNameString的变更通知,使用自动通知

    if ([key   isEqualToString:@"dongNameString"])

    {

        returnYES;

    }

// 确保调用了父类的automaticallyNotfiesObserversForKey方法

    return [superautomaticallyNotifiesObserversForKey:key];

}


  ///  在  ViewController.h 里   主人的家//

#import <UIKit/UIKit.h>

#import "dogName.h"

@interface ViewController :UIViewController

{

      dogName *dogname;

}

@property (weak,nonatomic)IBOutlet UILabel *dogNameLable;  //在视图上显示哪个狗在看家

@end


  ///  在  ViewController.m 里   //

#import "ViewController.h"

#import "dogName.h"

@interfaceViewController ()


@end


@implementation ViewController

@synthesize dogNameLable;


- (void)viewDidLoad

{

    [superviewDidLoad];

    dogname = [[dogName  alloc]init];

   

 //注册观察者 狗主人

    [dogname    addObserver:self

 forKeyPath:@"dongNameString"

                options:(NSKeyValueObservingOptionNew |

 NSKeyValueObservingOptionOld)

context:NULL];

//观察者对象的属性进行操作    看看哪条狗在看家

   dogNameLable.text = [dogname  valueForKey:@"dongNameString"];

 

    

}


// 处理变更通知  狗主人的眼睛 能观察到是否有其他的狗来接班

- (void)observeValueForKeyPath:(NSString *)keyPath

  ofObject:(id)object

                        change:(NSDictionary *)change

                       context:(void *)context

{

    

NSLog(@"%@",keyPath);

    if ([keyPath isEqual:@"dongNameString"])

    {

    dogNameLable.text=[change objectForKey:NSKeyValueChangeNewKey];

    }else

    {

        [super   observeValueForKeyPath:keyPath

                             ofObject:object

                               change:change

                              context:context];

        

    }

}


//搬家了就要       删除观察者

-(void)dealloc

{

    

   [dogname   removeObserver:self   forKeyPath:@"dongNameString"];

}


- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

遛狗的demo:   http://download.csdn.net/detail/lengshengren/6506879



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值