Key-Value Observing (键值监測)

Key-Value Observing (键值监測)

简单介绍

KVO是一套当目标对象的属性值改变时观察者对象能够接受到通知的机制。必须先理解KVC才干更好的理解KVO,前者是后者的实现基础。

这种通信机制在MVC设计模式非常是常见

实现过程简单来说分为3步:

1、加入观察这和监測对象

2、监測对象改变

3、收到值改变通知,处理兴许逻辑

举个生活中的样例就是给银行卡开通短信通知的业务,整体也是分3步“

1、去银行办理短信业务

2、账号財产变动

3、收到短信通知

KVO是框架级别的服务。无需自己发送通知。使用方便,基本不须要加入额外代码就可以使用。

详情

为了使用KVO。必须满足下面3步

1、目标对象的属性,必须支持KVO

2、注冊观察者与被观察者addObserver:forKeyPath:options:context:

3、观察者必须实现observeValueForKeyPath:ofObject:change:context:方法

第一步、确保目标支持KVO

被监測的目标对象的属性支持KVO必须满足下面条件:

1、目标对象的属性必须支持KVC。对于1对1属性简单来说就是实现set和get方法。

详情和1对多请阅读官方说明。系统已有类及子类自己主动支持。放心使用。

2、自己主动和手动属性通知

目标对象必须能发出属性变化通知。系统默认支持,也可自己定义。

系统默认支持,且支持的非常好,一般无需自己定义。

//假设须要自己定义,须要又一次此方法,默认返回YES
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key;

//在set方法中手动调用,变化类型仅仅是针对NSKeyValueChangeSetting
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;

比如

//假设有属性
@property (nonatomic,copy)NSString *name;

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {

    BOOL automatic = NO;
    /* 仅仅自己定义指定属性,其他仍然自己主动发送通知 */
    if ([theKey isEqualToString:@"name"])
    {
        //在set方法中手动调用相关方法
        automatic = NO;
    }
    else
    {
        //此方法默认返回YES
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

- (void)setName:(NSString *)name
{
    //即将变化
    [self willChangeValueForKey:@"name"];

    _name = name;

    //已经变化
    [self didChangeValueForKey:@"name"];
}

//假设说仅仅有值不相等时才发送通知。提升性能
- (void)setName:(NSString *)name
{
    if (![name isEqualToString:_name])
    {

        [self willChangeValueForKey:@"name"];

        _name = name;

        [self didChangeValueForKey:@"name"];
    }
}

假设涉及1对多的容器类,须要自己实现 NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, NSKeyValueChangeReplacement三种操作相应的方法,比如

//Keys为属性名称
- (void)removeKeysAtIndexes:(NSIndexSet *)indexes {
    [self willChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"keys"];

    // Remove the transaction objects at the specified indexes.

    [self didChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"keys"];
}

3、属性依赖

假设目标对象属性存在依赖关系,注冊合适的依赖Keys。核心方法为

第一种、
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
说明:
1、返回目标属性依赖属性的KeyPath的Set。当对象注冊后。KVO自己主动监測该对象全部的KeyPaths。
2、其默认实现从对象所属类的方法列表中匹配方法:+keyPathsForValuesAffecting<Key>(<Key>为属性名。比方Name),假设存在运行并返回结果;假设不存在向底层寻找已经废弃的方法+setKeys:triggerChangeNotificationsForDependentKey:
3、能够用来替换手动调用-willChangeValueForKey:/-didChangeValueForKey:来实现属性依赖的解决方式
4、不能在已有类的Category中使用,在Category禁止重写此方法,能够使用+keyPathsForValuesAffecting<Key>来实现。

另外一种、
或者重写此格式+keyPathsForValuesAffecting<Key>(<Key>为属性名,比方Name)的方法名

比方说,姓名=姓+名;当二者任一变动时更新姓名

@property (nonatomic,copy)NSString *name;//姓名
@property (nonatomic,copy)NSString *firstName;//姓
@property (nonatomic,copy)NSString *lastName;//名

//又一次get方法。表明字段组成
-(NSString *)name
{
    return [NSString stringWithFormat:@"%@%@",_firstName,_lastName];
}

//通过此方法
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
 {

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"name"])
    {
        NSArray *affectingKeys = @[@"lastName", @"firstName"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}
或者
+ (NSSet *)keyPathsForValuesAffectingName
{
    return [NSSet setWithObjects:@"lastName", @"firstName", nil];
}

//改变值
- (void)viewDidLoad {
    [super viewDidLoad];

    [self setValue:@"张" forKey:@"firstName"];
    [self setValue:@"三" forKey:@"lastName"];

    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    //名称改变。刷新姓名
    [self setValue:@"龙" forKey:@"lastName"];

}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"NSKeyValueChangeOldKey:%@",change[NSKeyValueChangeOldKey]);
    NSLog(@"NSKeyValueChangeNewKey:%@",change[NSKeyValueChangeNewKey]);
}

//输出结果
2016-09-06 17:05:01.904 KVC[4192:307124] NSKeyValueChangeOldKey:张三
2016-09-06 17:05:01.904 KVC[4192:307124] NSKeyValueChangeNewKey:张龙

注意:以上关于属性依赖的处理方法不支持一对多的关系。比方说ViewController对象有一个totalNumber表示总数和属性datas数组,数组中Data的对象,对象含有number属性。

/* Data对象 */
@interface Data : NSObject

@property (nonatomic,assign)NSInteger number;

@end

/* ViewController对象 */
@interface ViewController ()

@property (nonatomic,assign)NSInteger totalNumber;

@property (nonatomic,strong)NSArray *datas;

@end

能够採用下面方法解决

1、注冊每一个Data对象的年龄属性为监測属性,ViewController对象为观察者,data.number变化时。使用集合运算符求和。然后设置ViewController的totalNumber属性值

- (void)viewDidLoad {
    [super viewDidLoad];

    /* 创建Data对象 */
    Data * data1 = [[Data alloc] init];
    data1.number = 0;

    Data *data2 = [[Data alloc] init];
    data2.number = 0;

    Data *data3 = [[Data alloc] init];
    data3.number = 0;

    /* self.datas属性赋值 */
    [self setValue:@[data1,data2,data3] forKey:@"datas"];

    /* 监測self.datas中每一个data对象的number属性 */
    //(0, 3) 中0表示index从0開始,0表示长度3。也就是index(0、1、2);可是不能使得self.datas数组越界
    NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)];

    [self.datas addObserver:self toObjectsAtIndexes:set forKeyPath:@"number" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    /* 监測totalNumber属性 */
    [self addObserver:self forKeyPath:@"totalNumber" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    /* 改变值,查看输出结果 */
    [data1 setValue:@"1" forKey:@"number"];
    [data2 setValue:@"1" forKey:@"number"];
    [data3 setValue:@"1" forKey:@"number"];

}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"number"])
    {
        [self updateTotalNumber];
    }
    else if ([keyPath isEqualToString:@"totalNumber"])
    {
        NSLog(@"%@--%@",keyPath,change);
    }
}

//更新总数
- (void)updateTotalNumber
{

    NSNumber *total = [self valueForKeyPath:@"[email protected]"];

    [self setValue:total forKey:@"totalNumber"];
}

//输出结果
2016-09-07 14:10:10.694 KVC[3034:165515] totalNumber--{
    kind = 1;
    new = 1;
    old = 0;
}
2016-09-07 14:10:10.695 KVC[3034:165515] totalNumber--{
    kind = 1;
    new = 2;
    old = 1;
}
2016-09-07 14:10:10.695 KVC[3034:165515] totalNumber--{
    kind = 1;
    new = 3;
    old = 2;
}

以上代码中不涉及移除。依据须要加入代码,对象delloc之前。必须移除。

2、Core Data,自己主动实现相似的功能。

第二步、注冊

1、注冊通知

为了能够获取目标属性值改变的通知。须要注冊观察者和观察对象属性

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
參数说明:
observer:观察者对象,就是想收到变动通知的对象
keyPath:监測的目标属性的路径
options:决定了通知中内容和发送时间
context:C指针或者对象。传递參数,一般不用传NULL

比如在新建的project的ViewController中

@property (nonatomic,copy)NSString *name;

- (void)registerAsObserver
{

    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

}

注意:此方法不持有观察者对象、被观察对象、context,管理好其生命周期。

2、接受通知

当监測的目标对象的属性变化时。观察者将调用observeValueForKeyPath:ofObject:change:context: message,全部的观察者都必须实现此方法

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
keyPath:监測的目标属性的路径
object:观察者对象
change:变化内容
context:C指针或者对象,传递參数,一般不用传NULL

3、移除通知

当不再使用时,须要通过下面方法移除通知。

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

keyPath:监測的目标属性的路径
observer:观察者对象
context:C指针或者对象,传递參数,一般不用传NULL
以上两个方法,依据须要选择使用。

特别注意:NSArray、NSOrderedSet、NSSet不支持以上三个方法。调用会抛出异常。

第三步、属性变化

使用KVC方法,或者能够触发KVC方法使得监測的目标对象属性变化。

第四步、接收变化

当监測的目标对象的属性变化时。观察者将调用observeValueForKeyPath:ofObject:change:context: message,全部的观察者都必须实现此方法。在此方法中处理变化

以上第二、三、四步组成一次完整的KVO使用过程。下边关于一些參数的使用方法说明

參数说明

关于NSKeyValueObservingOptions

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
options:决定了通知中内容和发送时间

NSKeyValueObservingOptions是一个枚举类型

typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {

    /*通知dic中是否包括新值*/
    NSKeyValueObservingOptionNew = 0x01,

    /*通知dic中是否包括新值*/
    NSKeyValueObservingOptionOld = 0x02,

    /*加入此操作,通知dic中是否包括注冊通知前的初始值。假设目标属性是容器类,每一个元素都会触发通知发送*/
    NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04,

    /*加入此操作,每次值变化。将触发两次:1、变化前(dic中包括NSKeyValueChangeNotificationIsPriorKey,值为1,NSNumber类型)
    2、变化后
    */
    NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08
};

关于Change Dictionary

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
change:变化内容

其包括下面几种内容,能够使用下面字段取值

//值变化类型
FOUNDATION_EXPORT NSString *const NSKeyValueChangeKindKey;

//新值
FOUNDATION_EXPORT NSString *const NSKeyValueChangeNewKey;

//旧值
FOUNDATION_EXPORT NSString *const NSKeyValueChangeOldKey;

//容器类中,变化值所在位置,NSIndexSet类型
FOUNDATION_EXPORT NSString *const NSKeyValueChangeIndexesKey;

//是否值变化前,NSNumber类型
FOUNDATION_EXPORT NSString *const NSKeyValueChangeNotificationIsPriorKey NS_AVAILABLE(10_5, 2_0);

当中NSKeyValueChangeKindKey有下面几种类型

typedef NS_ENUM(NSUInteger, NSKeyValueChange)
{
    NSKeyValueChangeSetting = 1,//值变化
    NSKeyValueChangeInsertion = 2,//插入
    NSKeyValueChangeRemoval = 3,//移除
    NSKeyValueChangeReplacement = 4,//替换
};

上边的NSKeyValueChangeKindKey2、3、4分别相应着有序集合比方NSArray中增、删、改操作。

參数说明-代码演示样例

1、NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld

@property (nonatomic,copy)NSString *name;

//注冊
- (void)viewDidLoad {
    [super viewDidLoad];

    [self setValue:@"zwq" forKey:@"name"];

    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

   [self setValue:@"zwq2" forKey:@"name"];

}

//接收
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"NSKeyValueChangeKindKey:%@",change[NSKeyValueChangeKindKey]);
    NSLog(@"NSKeyValueChangeOldKey:%@",change[NSKeyValueChangeOldKey]);
    NSLog(@"NSKeyValueChangeNewKey:%@",change[NSKeyValueChangeNewKey]);
    NSLog(@"change dic:%@",change);
}

//输出结果
2016-09-06 14:58:55.349 KVC[3614:231751] NSKeyValueChangeKindKey:1
2016-09-06 14:58:55.351 KVC[3614:231751] NSKeyValueChangeOldKey:zwq
2016-09-06 14:58:55.351 KVC[3614:231751] NSKeyValueChangeNewKey:zwq2
2016-09-06 14:58:55.352 KVC[3614:231751] change dic:{
    kind = 1;
    new = zwq2;
    old = zwq;
}

从以上代码能够看出change中的key怎样取值,以及当中内容。

2、NSKeyValueObservingOptionInitial

@property (nonatomic,copy)NSString *name;

//注冊
- (void)viewDidLoad {
    [super viewDidLoad];

    [self setValue:@"zwq" forKey:@"name"];

    //为了明显观察值变化。多加入两个key
    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    [self setValue:@"zwq2" forKey:@"name"];

}

//接收
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"NSKeyValueChangeKindKey:%@",change[NSKeyValueChangeKindKey]);
    NSLog(@"NSKeyValueChangeOldKey:%@",change[NSKeyValueChangeOldKey]);
    NSLog(@"NSKeyValueChangeNewKey:%@",change[NSKeyValueChangeNewKey]);
    NSLog(@"change dic:%@",change);
}

//输出结果
2016-09-06 15:06:49.963 KVC[3654:237675] NSKeyValueChangeKindKey:1
2016-09-06 15:06:49.964 KVC[3654:237675] NSKeyValueChangeOldKey:(null)
2016-09-06 15:06:49.964 KVC[3654:237675] NSKeyValueChangeNewKey:zwq
2016-09-06 15:06:49.964 KVC[3654:237675] change dic:{
    kind = 1;
    new = zwq;
}

2016-09-06 15:06:49.964 KVC[3654:237675] NSKeyValueChangeKindKey:1
2016-09-06 15:06:49.965 KVC[3654:237675] NSKeyValueChangeOldKey:zwq
2016-09-06 15:06:49.965 KVC[3654:237675] NSKeyValueChangeNewKey:zwq2
2016-09-06 15:06:49.965 KVC[3654:237675] change dic:{
    kind = 1;
    new = zwq2;
    old = zwq;
}

对照1、2的输出结果,能够看出2中能够获得初始值。兴许值变化接收到的通知dic内容同1中一样(能够多改变几次赋值,观察结果)

3、NSKeyValueObservingOptionPrior

@property (nonatomic,copy)NSString *name;

//注冊
- (void)viewDidLoad {
    [super viewDidLoad];

    [self setValue:@"zwq" forKey:@"name"];

    //为了明显观察值变化,多加入两个key
    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionPrior|NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    [self setValue:@"zwq2" forKey:@"name"];
    [self setValue:@"zwq3" forKey:@"name"];

}

//接收
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"NSKeyValueChangeKindKey:%@",change[NSKeyValueChangeKindKey]);
    NSLog(@"NSKeyValueChangeOldKey:%@",change[NSKeyValueChangeOldKey]);
    NSLog(@"NSKeyValueChangeNewKey:%@",change[NSKeyValueChangeNewKey]);
    NSLog(@"NSKeyValueChangeNotificationIsPriorKey:%@",change[NSKeyValueChangeNotificationIsPriorKey]);
    NSLog(@"change dic:%@",change);
}

//输出结果
2016-09-06 15:17:16.325 KVC[3730:246941] NSKeyValueChangeKindKey:1
2016-09-06 15:17:16.326 KVC[3730:246941] NSKeyValueChangeOldKey:zwq
2016-09-06 15:17:16.326 KVC[3730:246941] NSKeyValueChangeNewKey:(null)
2016-09-06 15:17:16.326 KVC[3730:246941] NSKeyValueChangeNotificationIsPriorKey:1
2016-09-06 15:17:16.327 KVC[3730:246941] change dic:{
    kind = 1;
    notificationIsPrior = 1;
    old = zwq;
}
2016-09-06 15:17:16.327 KVC[3730:246941] NSKeyValueChangeKindKey:1
2016-09-06 15:17:16.327 KVC[3730:246941] NSKeyValueChangeOldKey:zwq
2016-09-06 15:17:16.327 KVC[3730:246941] NSKeyValueChangeNewKey:zwq2
2016-09-06 15:17:16.327 KVC[3730:246941] NSKeyValueChangeNotificationIsPriorKey:(null)
2016-09-06 15:17:16.328 KVC[3730:246941] change dic:{
    kind = 1;
    new = zwq2;
    old = zwq;
}

2016-09-06 15:17:16.328 KVC[3730:246941] NSKeyValueChangeKindKey:1
2016-09-06 15:17:16.328 KVC[3730:246941] NSKeyValueChangeOldKey:zwq2
2016-09-06 15:17:16.328 KVC[3730:246941] NSKeyValueChangeNewKey:(null)
2016-09-06 15:17:16.328 KVC[3730:246941] NSKeyValueChangeNotificationIsPriorKey:1
2016-09-06 15:17:16.328 KVC[3730:246941] change dic:{
    kind = 1;
    notificationIsPrior = 1;
    old = zwq2;
}
2016-09-06 15:17:16.328 KVC[3730:246941] NSKeyValueChangeKindKey:1
2016-09-06 15:17:16.329 KVC[3730:246941] NSKeyValueChangeOldKey:zwq2
2016-09-06 15:17:16.329 KVC[3730:246941] NSKeyValueChangeNewKey:zwq3
2016-09-06 15:17:16.329 KVC[3730:246941] NSKeyValueChangeNotificationIsPriorKey:(null)
2016-09-06 15:17:16.329 KVC[3730:246941] change dic:{
    kind = 1;
    new = zwq3;
    old = zwq2;
}

从以上代码输出结果不难看出:a、通知分开发送:变化前和变化后 b、变化前NSKeyValueChangeNewKey为空。可是NSKeyValueChangeNotificationIsPriorKey值为1;变化后反之。

结合以上3段代码结论:4种各有所用。能够单独使用,也能够组合使用。依据须要选择合适。作用简单概括:1.新、旧值 2.初始值 3.值变化前后。

4、NSKeyValueChangeKindKey

@interface ViewController ()

@property (nonatomic,strong)NSArray *datas;
@end

- (void)viewDidLoad {
    [super viewDidLoad];

    /* 创建Data对象 */
    Data * data1 = [[Data alloc] init];
    Data *data2 = [[Data alloc] init];
    Data *data3 = [[Data alloc] init];
    Data *data4 = [[Data alloc] init];

    /* self.datas属性赋值 */
    [self setValue:@[data1,data2,data3] forKey:@"datas"];

    /* 监測self.datas属性 */
    [self addObserver:self forKeyPath:@"datas" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

    //改动datas数组:增删改
    NSMutableArray *mutable_subdatas = [self mutableArrayValueForKeyPath:@"datas"];
    [mutable_subdatas addObject:data4];
    [mutable_subdatas removeObject:data4];
    [mutable_subdatas replaceObjectAtIndex:2 withObject:data4];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSLog(@"%@--%@",keyPath,change);
}

//输出结果
2016-09-07 14:46:50.366 KVC[3231:186568] datas--{
    indexes = "<_NSCachedIndexSet: 0x7f8591428c60>[number of indexes: 1 (in 1 ranges), indexes: (3)]";
    kind = 2;
    new =     (
        "<Data: 0x7f8591427b00>"
    );
}

2016-09-07 14:46:50.367 KVC[3231:186568] datas--{
    indexes = "<_NSCachedIndexSet: 0x7f8591428c60>[number of indexes: 1 (in 1 ranges), indexes: (3)]";
    kind = 3;
    old =     (
        "<Data: 0x7f8591427b00>"
    );
}

2016-09-07 14:46:50.367 KVC[3231:186568] datas--{
    indexes = "<_NSCachedIndexSet: 0x7f8591428c40>[number of indexes: 1 (in 1 ranges), indexes: (2)]";
    kind = 4;
    new =     (
        "<Data: 0x7f8591427b00>"
    );
    old =     (
        "<Data: 0x7f8591402350>"
    );
}

原文地址:https://www.cnblogs.com/zhchoutai/p/8726855.html

时间: 2024-11-08 00:36:00

Key-Value Observing (键值监測)的相关文章

xcode KVC:Key Value Coding 键值编码

赋值 // 能修改私有成员变量 - (void)setValue:(id)value forKey:(NSString *)key; - (void)setValue:(id)value forKeyPath:(NSString *)keyPath; - (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues; 取值 // 能取得私有成员变量的值 - (id)valueForKey:(NSString *)key; - (

ios中键值编码kvc和键值监听kvo的特性及详解

总结: kvc键值编码  1.就是在oc中可以对属性进行动态读写(以往都是自己赋值属性)           2. 如果方法属性的关键字和需要数据中的关键字相同的话                  3. 动态设置:setValue:属性值 forKey:属性名(用于简单的路径)/setValue:属性值 forKeyPath:属性名(用于复杂的路径)kvo键值监听  永久性的监听item属性值的改变,如果改变就从新设置             1.监听方法:[addObserver:self

深度理解Key-Value Observing 键值观察

前言   在上一阶段的开发过程中,我们大量使用了 KVO 机制,来确保页面信息的及时同步.也因此碰到了很多问题,促使我们去进一步学习 KVO 的相关机制,再到寻找更好的解决方案.鉴于 KVO 让人欲仙欲死的使用经历,在这里做一个简单分享.此分享的目的,更多的是在于点出 KVO 相关的技术点,供我们大家在学习和使用过程中做一个参考. 对于 KVO 的背后机制感兴趣的同学,可以直接看第三部分,KVC 和 isa-swizzling . 对于 替代方案感兴趣的同学,请直接跳到末尾的第五部分,有列出了目

KVO键值监听

KVO 键值监听:当我想知道一个对象的属性是否发生改变的时候 做出响应,就需要添加监听keypath 和 key的区别keypath会自动寻找子类的属性key只会寻找当前类的属性添加键值监听[person addObserver:self forKeyPath:@“属性” options:.....] 当键值发生改变的时候调用-(void)obserValueForKeyPath:(NSString ) 底层实现:运行的时候 创建一个当前类的子类,重写子类的set方法 系统 建立了一个子类,然后

iOS设计模式之KVO Key-Value Observing 键值观察者模式的简单实用和介绍

它提供一种机制,当指定的对象的属性被修改后,则监听者就会接受到通知. 就好像我们给手机定了一个闹钟,等到了制定的时间,闹钟就会响起,我们就会知道时间到了 这个过程中,我们就是监听者,闹钟就是被监听的对象 我们创建一个student类,使用KVO模式,给其中的username 属性添加监听者(观察者 XSStudent *su = [[XSStudentalloc] init]; su.name = @"zhangsan"; su.age = 12; //Observer 观察者是谁 /

php 获取数组第一个key 第一个键值对 等等

PHP 获取数组中的第一个元素或最后一个元素的值或者键值可以使用 PHP 自带的数组函数. PHP 获取数组中的第一个元素的值或者键值所使用的函数: current() - 返回数组中当前元素值(即:返回当前被数组内部指针指向的元素的值). reset() - 函数把数组的内部指针指向第一个元素,并返回这个元素的值. key() - 返回数组内部指针指向的元素的索引(即:键值). PHP 获取数组中的最后一个元素的值或者键值所使用的函数: end() - 函数将数组内部指针指向最后一个元素,并返

Unity3d 中键值监听方法

unity3d的api中没有负责监听键值的方法,不过unity的input类是通过c#类获取各类监听事件,所以我们可以通过c#类监听,方法如下: void OnGUI() { Event e = Event.current; if (e.isKey) { if (Event.current.keyCode == KeyCode.Joystick2Button0){ //你的逻辑} } } 过程很简单,就不多说,注意该事件只能在OnGUI函数中起作用. 转载请标明出处,from 博客园 HemJo

K-V-C 键值观察机制

在两个不同的控制器之间传值是iOS开发中常有的情况,应对这种情况呢,有多种的应对办法.kvc就是其中的一种,所以,我们就在此解释之.   key value observing  键值观察,给人一种高冷的感觉,其实,我们可以用一个通俗的例子来解释之.就拿美俄之间的间谍来举例子.美俄是两个各自独立的国家,但是为了各自的利益,彼此之间勾心斗角,不断的爆出间谍丑闻.打住!从政治的深渊回到技术层面O(∩_∩)O.美国想知道俄罗斯的最新的导弹技术,于是派间谍收集情报,(kvo的第一步:注册观察者-美国,监

Key-Value Observing (键值监测)

Key-Value Observing (键值监测) 简介 KVO是一套当目标对象的属性值改变时观察者对象能够接受到通知的机制.必须先理解KVC才能更好的理解KVO,前者是后者的实现基础. 这样的通信机制在MVC设计模式很是常见 实现过程简单来说分为3步: 1.添加观察这和监测对象 2.监测对象改变 3.收到值改变通知,处理后续逻辑 举个生活中的例子就是给银行卡开通短信通知的业务,总体也是分3步" 1.去银行办理短信业务 2.账号财产变动 3.收到短信通知 KVO是框架级别的服务,无需自己发送通