IOS KVC和KVO的使用

KVC键值编码:

KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:

  • 动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)

  • 动态读取: valueForKey:属性名 、valueForKeyPath:属性名(用于复合路径)

下面来看看几个例子就会明白KVC的好处了

场景一:给一个student的name和age赋值

@interface Student : NSObject

@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *name;

@end

//不使用KVC时
 NSDictionary *dic = @{@"name":@"张三",@"age":@20};

 Student *sudent = [[Student alloc] init];
 student.name = dic[@"name"];
 student.age = dic[@"age"];

//这只是自己定义的简单的字典,用起来还不算复杂,要是在项目开发过程中会有很多的属性,再这样一个个去赋值显得麻烦很多

//使用kvc赋值

//在Student.h文件中增加一个自定义初始化的方法
- (instancetype)initWithDic:(NSDictionary *)dic;

//student.m中实现该方法
#import "Student.h"

@implementation Student

- (instancetype)initWithDic:(NSDictionary *)dic {

    if (self = [super init]) {

        [self setValuesForKeysWithDictionary:dic];
    }
    return self;
}

//在进行赋值的时候就只需要调用一个初始化方法即可,不在需要额外的设置
  Student *student = [[Student alloc] initWithDic:dic];
   NSLog(@"student.name = %@, student.age = %d",student.name, student.age);
@end

场景二.复合路径的赋值方法

#import "Person.h"
@class Account;
@interface Person : NSObject {

    @private //通过KVC私有属性一样可以在外界赋值
    int _age;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) Account *account; //账户
@end

//假如人有个账户
@interface Account : NSObject

@property (nonatomic, assign) float blance; //余额

@end


//主要实现代码
Person *person1 = [[Person alloc] init];

//setValue:属性值 forKey:属性名(用于简单路径
[person1 setValue:@"Kenshin" forKey:@"name"];
[person1 setValue:@28 forKey:@"age"];//注意即使一个私有变量仍然可以访问

NSLog(@"person1's name is :%@, age is %@",person1.name, [person1 valueForKey:@"age"]);

//按路径赋值
person1.account = [[Account alloc] init];
//setValue:属性值 forKeyPath:属性路径(用于复合路径
[person1 setValue:@10000.0 forKeyPath:@"account.blance"];
NSLog(@"person1's balance is %.2f",[[person1 valueForKeyPath:@"account.blance"] floatValue];

场景三:赋值字典转模型对象

#import <Foundation/Foundation.h>

@interface Teacher : NSObject

@property (nonatomic, copy) NSString *teacherName;

//老师下有许多学生
@property (nonatomic, strong) NSArray *students;

//初始化方法
- (instancetype)initWithWithDic:(NSDictionary *)dic;
@end

#import "Teacher.h"
#import "Student.h"

@implementation Teacher

- (instancetype)initWithWithDic:(NSDictionary *)dic {

    if (self = [super init]) {

        [self setValue:dic[@"teacherName"] forKey:@"teacherName"];

        NSArray *array = dic[@"students"];
        NSMutableArray *students = [NSMutableArray array];
        for (NSDictionary * dic in array) {

            Student *student = [[Student alloc] initWithDic:dic];
            [students addObject:student];
        }

        [self setValue:students forKey:@"students"];
    }


    return self;
}

#import <Foundation/Foundation.h>

@interface Student : NSObject

@property (nonatomic, assign) int age;

@property (nonatomic, copy) NSString *name;

- (instancetype)initWithDic:(NSDictionary *)dic;

@end

#import "Student.h"

@implementation Student


- (instancetype)initWithDic:(NSDictionary *)dic {

    if (self = [super init]) {

        [self setValuesForKeysWithDictionary:dic];
    }


    return self;
}

@end


//模型转换实现代码
NSDictionary *dic = @{@"teacherName":@"王麻子",
                          @"students":@[@{@"name":@"张三",
                                          @"age":@20},
                                        @{@"name":@"李四",
                                          @"age":@30}
                                  ]};


    Teacher *teacher = [[Teacher alloc] initWithWithDic:dic];
    NSLog(@"teacher  = %@, teacher.name = %@", teacher, teacher.teacherName);

    Student *student = teacher.students[0];
    NSLog(@"student.name = %@, student.age = %d",student.name, student.age);

    打印效果如下:
2016-09-12 14:25:07.539 KCVAndKVO[3780:1519551] teacher  = <Teacher: 0x100701540>, teacher.name = 王麻子
2016-09-12 14:25:07.540 KCVAndKVO[3780:1519551] student.name = 张三, student.age = 20
Program ended with exit code: 0

KVO键值监听


//Account.h
#import <Foundation/Foundation.h>

@interface Account : NSObject

@property (nonatomic, assign) float blance; //余额

@end


//Person.h
#import <Foundation/Foundation.h>

@class Account;

@interface Person : NSObject {

    @private

    int _age;
}

@property (nonatomic, copy) NSString *name;

@property (nonatomic, strong) Account *account; //账户

/**
 *  显示人员信息
 */

- (void)showMessage;

@end


//Person.m
#import "Person.h"
#import "Account.h"
@implementation Person

- (void)showMessage {

    NSLog(@"name = %@, age = %d",_name, _age);
}

#pragma mark -- 设置人员账户

- (void)setAccount:(Account *)account {

    _account = account;
    //添加对Account的监听
    [self.account addObserver:self forKeyPath:@"blance" options:NSKeyValueObservingOptionNew context:nil];
}

#pragma mark -- 重写observeValueForKeyPath方法,当账户余额变化后此处获得通知
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {

    if ([keyPath isEqualToString:@"blance"]) {//这里指出了blance属性

        NSLog(@"keyPath = %@, object = %@, newValue = %.2f, context = %@", keyPath, object, [[change objectForKey:@"new"] floatValue], context);
    }
}

#pragma mark -- 重写销毁的方法

- (void)dealloc {
    [self.account removeObserver:self forKeyPath:@"blance"];
}


@end


//实现代码:
Person *person1 = [[Person alloc] init];
    person1.name = @"Kenshin";
    Account *account = [[Account alloc] init];
    account.blance = 1000000.0;
    person1.account = account;

    account.blance = 20000000.0; //注意执行到这一步会触发监听器回调observeValueForKeyPath方法打印相关信息

   //打印结果如下:2016-09-12 15:15:55.612 KCVAndKVO[3812:1725219] keyPath = blance, object = <Account: 0x100106240>, newValue = 20000000.00, context = (null)
Program ended with exit code: 0

这篇文章只介绍KVC和KVO的基本使用,帮助理解和使用,如有错误的地方还请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值