键值编码(KVC)和键值观察(KVO)

KVC( Key value coding )

Animal.m

@interface Animal ()
{
    
    NSString *_dna;
}
@property (nonatomic,copy) NSString *DNA;
@property (nonatomic,strong) Dog *dog;

@end
//当设置的实例变量为标量,且赋值为空,
//标量: int, float, double;  NSString是OC对象
- (void)setNilValueForKey:(NSString *)key{
    NSLog(@"-----Nil------");
}
//当取得值没有定义时
- (id)valueForUndefinedKey:(NSString *)key {
    return key;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"--------key: %@", key);
}

Dog.m

@interface Dog ()
{
    NSString *_dogName;
}
@end

ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Animal *animal = [Animal new];
    [animal setValue:@"---animal--dna---" forKey:@"_dna"];
    
    NSString *dna =  (NSString*)[animal valueForKey:@"_dna"];
    NSLog(@"dna = %@",dna);
    //用property生成的变量会自动生成带下滑线的,所以两个都一样
    [animal setValue:@"lol" forKey:@"_DNA"];
    NSString *DNA = (NSString*)[animal valueForKey:@"_DNA"];
    NSLog(@"DNA = %@",DNA);

    //keyPath用于隔级赋值
    Dog *dog = [Dog new];
//    [dog setValue:@"laohei" forKey:@"name"];
    [animal setValue:dog forKey:@"dog"];
    [animal setValue:@"--dogName--" forKeyPath:@"dog.dogName"];
    
    NSString *dogName = [animal valueForKeyPath:@"dog.dogName"];
    NSLog(@"dogName = %@",dogName);

}

KVO ( Key Value Oberser )

Animal.h

@interface Animal : NSObject
@property (nonatomic, assign)double height;
@end

ViewController

@interface ViewController ()
{
    Animal *_animal;
}
@end
@implementation ViewController
- (void)viewDidLoad {
    _animal = [Animal new];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        _animal.height = 11;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
            _animal.height = 22;
        });
       
    });
    
    [_animal addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    
}
//观察对象应该设为全局的,不然没法执行此函数观察者就会被销毁
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    NSLog(@"keyPath:%@",keyPath);
    NSLog(@"change:%@",change);
    NSLog(@"--value:%@",change[@"new"]);
}
//在观察对象销毁的时候,观察者一定要销毁
- (void)dealloc{

    [_animal removeObserver:self forKeyPath:@"height"];
}

@end

当Animal中此函数的返回值为NO时

+(BOOL)automaticallyNotifiesObserversOfHeight{

    return NO;
}

如果想让观察者知道改变的时机,则应该写代码如:

    [ _animal willChangeValueForKey:@"height"];
    _animal.height = 11;
    [ _animal didChangeValueForKey:@"height"];

你可能感兴趣的:(键值编码(KVC)和键值观察(KVO))