KVC和KVO
前言
相信在OC里面自学最有难度就是这个KVC和KVO了,很多人都不明白这个东西是什么,经过老师的讲解和我自己的理解,我是这样看的:KVC是在原来OC旧版本里面还没有设置器跟访问器的时候,用于对受保护的成员变量进行设置和访问的,所以我们要用KVC进行读写,在现在,KVC最大的作用就是动态访问某些变量的时候,缩减代码量,提高我们程序的可扩展性。
KVC
设计模式 -观察者模式
设计模式是用来解决某一特定问题
观察者模式
什么是观察者模式?
在工程中,一些类去观察‘A’类,当‘A’类发生变化时,这些类就会收到消息,做出相应反应。
什么时候使用观察者模式?
当一个类需要发送消息给多个类的时候,就用观察者模式。
观察者模式的作用?
一对多的消息发送
在OC中如何实现观察者模式?
OC中,观察者模式的设计基础,KVC/KVO
KVC(键值编码 Key-Value Coding)
KVC提供了一种在运行时而非编译时动态访问对象属性与实例变量的方式。
创建一个学生Student的类
@interface Student : NSObject
{
NSString *_name;
NSInteger _age;
}
@property (nonatomic,strong)NSString *address;
重写description方法
@implementation Student
-(NSString *)description{
return [NSString stringWithFormat:@"My name is %@,%lu years old,living in %@",_name,_age,_address];
}
setValue forKey和valueForKey
设置一个学生类的对象,以及用setValue forKey的方式对它的成员变量赋值。
Student *stu1=[Student new];
[stu1 setValue:@"Rick" forKey:@"_name"];
[stu1 setValue:@25 forKey:@"_age"];
[stu1 setValue:@"GZ" forKey:@"_address"];
NSLog(@"%@",stu1);
用valueForKey进行访问
NSString *name=[stu1 valueForKey:@"_name"];
NSNumber *age=[stu1 valueForKey:@"_age"];
NSString *address=[stu1 valueForKey:@"_address"];
NSLog(@"name = %@, age = %@,address = %@",name,age,address);
动态访问
动态访问某些属性时,使用一些可以运行时而不是编译时改变的值
student.h文件中
@property (nonatomic,assign)int p1;
@property (nonatomic,assign)int p2;
@property (nonatomic,assign)int p3;
-(int)getValuePropertyName:(NSString *)name;
-(int)getNewValuePropertyName:(NSString *)name;
我们可以通过写两个PropertyName方法去说明一下动态访问
student.m文件中
-(int)getValuePropertyName:(NSString *)name{
NSString *stu1=@"p1";
NSString *stu2=@"p2";
NSString *stu3=@"p3";
if ([stu1 isEqualToString:name ]) {
return self.p1;
}
else if ([stu2 isEqualToString:name ]) {
return self.p2;
}
else if ([stu3 isEqualToString:name ]) {
return self.p3;
}
else
return 0;
}
-(int)getNewValuePropertyName:(NSString *)name{
NSNumber *number=[self valueForKey:name];
return [number intValue];
}
主函数main.m
stu1.p1=1;
stu1.p2=2;
stu1.p3=3;
int a=[stu1 getValuePropertyName:@"p1"];
NSLog(@"%d",a);
int b=[stu1 getNewValuePropertyName:@"p1"];
NSLog(@"%d",b);
Book *book=[[Book alloc]init] ;
键路径编码
@interface Book : NSObject
{
NSString *_bookName;
}
在student.h文件中导入Book的头文件:#import “Book.h”
在主函数main.m中
[stu1 setValue:book forKeyPath:@"_book"];
[stu1 setValue:@"葵花宝典,欲练神功" forKeyPath:@"_book._bookName"];
NSString *bookName=[stu1 valueForKeyPath:@"_book._bookName"];
NSLog(@"bookName = %@",bookName);
KVO
KVO的由来:
在编程的过程中,我们经常需要判断目标是否发生变化,以便及时地做出对应的处理,此时苹果公司就提供了一种策略,即‘OC运行时’提供了‘KVO’技术,其中‘KVO’是基于‘KVC’实现
KVO的实现:
1.注册成为观察者
2.观察者定义KVO回顾
3.移除观察者
*/
Hero *hero=[Hero new];
[hero setValue:@100 forKey:@"_hp"];
Observer *observer = [[Observer alloc]initWithHero:hero];
[hero setValue:@300 forKey:@"_hp"];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(Time:) userInfo:nil repeats:YES];
_hero = hero;
_observer=observer;
}
-(void)Time:(NSTimer *)timer{
NSUInteger _cutHP=[[_hero valueForKey:@”_hp”]integerValue];
_cutHP -=50;
if (_cutHP<=0) {
NSLog(@"英雄挂了");
[_hero setValue:@0 forKey:@"_hp"];
[timer invalidate];
}
else{
[_hero setValue:@(_cutHP) forKey:@"_hp"];
}
}
#import <Foundation/Foundation.h>
#import "Hero.h"
@interface Observer : NSObject
@property (nonatomic,strong)Hero *hero;
-(id)initWithHero:(Hero *)hero;
@end
-(id)initWithHero:(Hero *)hero{
if (self =[super init]) {
self.hero=hero;
//1.注册成为观察者
/*表示接受通知的对象,即观察者,通常self
建路径参数,要观察的键路径
标志KVO希望变化如何传递给观察者,这些值可以使用‘|’进行多选
上下文内存区,通常为nil
*/
[self.hero addObserver:self forKeyPath:@"_hp" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
//定义回溯
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context{
NSLog(@"%@",[change objectForKey:NSKeyValueChangeNewKey]);
}
-(void)dealloc{
NSLog(@"我挂了");
/*
移除的观察者对象
观察的键路径
*/
[self.hero removeObserver:self forKeyPath:@"_hp"];
}
@interface Hero : NSObject
{
NSUInteger _hp;
}
@end