一.键值编码(KVC)的使用
键值编码是指:将表示对象包含的信息的字符串作为键值使用,来间接访问该信息的方式.
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p1 = [[Person alloc] init];
// p1->_age
// 这个方法会按照关键字先查找,如果没有,会自动加上下划线 '_';
[p1 setValue:@"xiaoqiang" forKey:@"name"];
NSString *name = [p1 valueForKey:@"name"];
NSLog(@"name:%@", name);
// 子类通过键值编码也拥有了父类的私有属性
Student *stu = [[Student alloc] init];
[stu setValue:@"man" forKey:@"gender"];
NSString *gender = [stu valueForKey:@"gender"];
NSLog(@"gender:%@", gender);
二.观察者模式(KVO)
观察者模式 : 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.
优点 : 对象之间解耦和,某个对象改变,不需要修改另一个对象.
事件 : 小孩变脏,保姆给小孩洗澡
(1) 产生事件的对象代码
Child.h
#import <Foundation/Foundation.h>
@interface Child : NSObject
@property(nonatomic, assign) NSInteger cleanValue;
@property(nonatomic, assign) NSInteger happyValue;
@end
Child.m
#import "Child.h"
@implementation Child
- (instancetype)init
{
self = [super init];
if (self) {
self.cleanValue = 100;
self.happyValue = 100;
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(timeAc:)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)timeAc:(NSTimer *)timer {
// 观察者,可以观察值的变化,但是系统设定如果观察者要响应值的变化,必须通过设置器方法修改值
// _cleanValue --;
self.cleanValue = _cleanValue - 2;
self.happyValue = _happyValue - 3;
NSLog(@"cleanValue:%ld", _cleanValue);
NSLog(@"happyValue:%ld", _happyValue);
}
(2) 响应事件的对象代码
Nanny.h
#import <Foundation/Foundation.h>
#import "Child.h"
@interface Nanny : NSObject
{
Child *_child;
}
- (instancetype)initWithChild:(Child *)child;
@end
Nanny.m
#import "Nanny.h"
@implementation Nanny
/*
1.观察者可以实时响应数据的改变
2.观察者要手动释放,在dealloc方法里 调用removeObserver
*/
/*
1.哪个类响应事件,代码写在哪个类
2.给小孩增加观察者
3.addObserver:self----苹果已经在内部定义好观察者,只需在此传入响应事件对象
4.forKeyPath:就是观察的属性
5.options:传递给接收者的值的类型,旧的还是新的
6.context:暂时用不到,可为空
*/
- (instancetype)initWithChild:(Child *)child {
self = [super init];
if (self) {
_child = child;
[_child addObserver:self forKeyPath:@"cleanValue" options:NSKeyValueObservingOptionNew context:nil];
[_child addObserver:self forKeyPath:@"happyValue" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
/*object:是观察的对象,在这里指child,可以用类型强转
*change:是一个字典,里面包含了观察属性的值,新的,旧的
*多个观察者,用if判断关键属性是否相等执行相应操作
*/
// 当要观察多个属性时,判断传递给接收者的值是否为cleanValue
if ([keyPath isEqualToString:@"cleanValue"]) {
NSNumber *valueObj = change[@"new"];
NSInteger value = [valueObj integerValue];
if (value < 95) {
NSLog(@"保姆给小孩洗澡");
// 通过objcet取得小孩对象
Child *ch = (Child *)object;
// 重新设置小孩的值
ch.cleanValue = 100;
}
}
// 判断传递给接受者的值是否为happyValue
if ([keyPath isEqualToString:@"happyValue"]) {
NSNumber *valueObj = [change valueForKey:@"new"];
NSInteger value = [valueObj integerValue];
if (value < 90) {
NSLog(@"保姆逗小孩玩");
Child *ch = (Child *)object;
ch.happyValue = 100;
}
}
}
- (void)dealloc {
[_child removeObserver:self forKeyPath:@"cleanValue"];
[_child removeObserver:self forKeyPath:@"happyValue"];
}
三.通知(NSNotificationCenter)
通知和之前的KVO功能很像,也是用于监听操作的,但是和KVO不同的是,KVO只用来监听属性值的变化,这个发送监听的操作是系统控制的,我们控制不了,我们只能控制监听操作,我们只能接受.但是通知就不一样了,他的监听发送也是又我们自己控制,我们可以在任何地方任何时机发送一个通知,从这一点看来,通知的使用场景更为广泛了.
事件 : 小孩变脏,保姆给小孩洗澡
(1) 产生事件的对象代码
Child.h
#import <Foundation/Foundation.h>
@interface Child : NSObject
@property (nonatomic, assign) NSInteger cleanValue;
@end
Child.m
#import "Child.h"
@implementation Child
- (instancetype)init
{
self = [super init];
if (self) {
_cleanValue = 100;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAC: userInfo:nil
repeats:YES];
}
return self;
}
- (void)timeAC:(NSTimer *)timer {
self.cleanValue --;
NSLog(@"cleanValue:%ld", _cleanValue);
/*
postNotificationName:通知名字
object:发通知的对象
*/
if (_cleanValue < 90) {
// 发出一个通知
NSLog(@"发出需要洗澡的通知");
[[NSNotificationCenter defaultCenter] postNotificationName:@"cleanValueNotification" object:self];
}
}
@end
(2) 影响事件的对象代码
Nanny.h
#import <Foundation/Foundation.h>
@interface Nanny : NSObject
@end
Nanny.m
#import "Nanny.h"
#import "Child.h"
@implementation Nanny
- (instancetype)init{
self = [super init];
if (self) {
// 注册一个通知接收器,监听名字为"cleanValueAction"的通知
// addObserver:在这里就是保姆为接收者
// selector:接到通知后调用的方法
// name:指定接收通知的名字
// object:指定接收某个对象的通知
// _child = child;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cleanValueAction:) name:@"cleanValueNotification" object:nil];
}
return self;
}
- (void)cleanValueAction:(NSNotification *)notification {
NSLog(@"收到给小孩洗澡的通知");
Child *child = (Child *)notification.object;
child.cleanValue = 100;
}
- (void)dealloc {
// 指定名字移除接收器
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"cleanValueAction" object:nil];
}