iOS学习笔记-----KVC,KVO与通知初探

本文介绍了KVC、KVO和通知在对象状态管理中的使用方法,包括键值编码(KVC)、观察者模式(KVO)和通知机制在对象属性变化监控上的应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.键值编码(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];

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值