/* KVC是键值编码 提供一种间接访问对象属性的机制,而不是通过getter和setter 1.为指定属性设置值:setValue:属性值 forKey:属性名称 2.获取指定属性值: valueForKey:属性名称 KVO是键值监听 只有通过KVC改变对象的属性值,才能被监听到 1.为某对象的某属性设置监听:addObserver:forKeyPath:options:context: 2.为key路径删除指定监听: removeObserver:forKeyPath:context: */ #import "ViewController.h" #import "JYPerson.h" @interface ViewController () @property(nonatomic,strong)JYPerson *person; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; JYPerson *person=[[JYPerson alloc]init]; [person setValue:@"顾金跃" forKey:@"name"]; // [person setName:@"顾金跃123"]; // person.name=@"顾金跃321"; [person setValue:@"173.5" forKey:@"height"]; [person setValue:@"135" forKey:@"weight"]; NSLog(@"姓名:%@ 身高:%@ 体重:%@",person.name,person.height,person.weight); NSLog(@"姓名:%@ 身高:%@ 体重:%@",[person valueForKey:@"name"],[person valueForKey:@"height"],[person valueForKey:@"weight"]); [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil]; [person addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew context:nil]; [person addObserver:self forKeyPath:@"weight" options:NSKeyValueObservingOptionNew context:nil]; self.person=person; [self addButton]; } -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { NSLog(@"被修改的keyPath为:%@ 被修改的对象为:%@ 新被修改的属性值为:%@ 被修改的上下文为:%@",keyPath,[object class],[change objectForKey:@"new"],context); NSLog(@"%@",self.person.name); } -(void)dealloc { [self.person removeObserver:self forKeyPath:@"name"]; [self.person removeObserver:self forKeyPath:@"height"]; [self.person removeObserver:self forKeyPath:@"weight"]; } -(void)addButton { UIButton *button=[UIButton buttonWithType:UIButtonTypeContactAdd]; button.frame=CGRectMake(100, 100, 50, 50); [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; } -(void)buttonClick { NSLog(@"点击"); self.person.name=@"123"; } @end
<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">当某个类的对象第一次被观察时,</span><span style="font-family: Arial; font-size: 14px; line-height: 26px; color: rgb(255, 0, 0);">系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。 派生类在被重写的 setter 方法实现真正的通知机制</span><span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">,就如前面手动实现键值观察那样。这么做是基于设置属性会调用 setter 方法,而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值,如果仅是直接修改属性对应的成员变量,是无法实现 KVO 的。</span><br style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;" /><span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制。此外,派生类还重写了 dealloc 方法来释放资源。</span>