iOS_KVC:Key-Value Coding-1(使用)

在这里插入图片描述


例如有这样一个类:

@interface MOPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, strong) MOPerson *father;
@end

一、访问对象属性

如有person一个对象:

MOPerson *person = [MOPerson personWithName:@"momo"];

1.Getting Attribute 获取属性

  1. 使用方法valueForKey:获取对象的属性
[person valueForKey:@"name"];
  1. 使用方法valueForKeyPath:可以访问属性的属性,采用点语法
[person valueForKeyPath:@"father.name"];

以上2个方法如果Key值不对(即该属性不存在),则会触发valueForUndefinedKey:方法,默认会抛出NSUndefinedKeyException异常,导致crash。

  • 我们也可以重写该类的此方法,打印出log,避免crash:
- (id)valueForUndefinedKey:(NSString *)key {
  NSLog(@"Error: valueForUndefinedKey: %@", key);
  return nil;
}
  1. 使用方法dictionaryWithValuesForKeys:返回一个字典包含,给出的keys的values
NSDictionary *dic = [person dictionaryWithValuesForKeys:@[@"name", @"age"]];
NSLog(@"%@", dic);
//  输出:
//  age = "<null>";
//  name = lili;

注意:这里没有的key(属性),也会返回一个"<null>"

2.Setting Attribute 设置属性

  1. 使用方法setValue:forKey:修改对象的属性
[person setValue:@"miki" forKey:@"name"];
  1. 使用方法setValue:forKeyPath:修改对象的属性的属性,采用点语法
[person setValue:@"baba" forKeyPath:@"father.name"];
  1. 使用方法setValuesForKeysWithDictionary:将给出的values设置给 给出的keys(属性)
[person setValuesForKeysWithDictionary:@{@"name":@"kiki", @"age":@""}];

以上3个方法如果Key值不对(即该属性不存在),则会触发setValue:forUndefinedKey:方法,默认会抛出NSUndefinedKeyException异常,导致crash。

  • 我们也可以重写该类的此方法,打印出log,避免crash:
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
  NSLog(@"Error: setValue:%@ forUndefinedKey: %@", value, key);
}

二、访问集合属性

例如我有这个属性: persons 数组

@property (nonatomic, strong) NSMutableArray<MOPerson *> *persons;
// 初始化:
MOPerson *p1 = [MOPerson personWithName:@"momo"];
p1.age = 18;
MOPerson *p2 = [MOPerson personWithName:@"lili"];
p2.age = 20;
self.persons = [@[p1, p2] mutableCopy];
// 获取数组里所有 person 的 name
NSArray<NSNumber *> *ages = [self.persons valueForKeyPath:@"age"];
NSLog(@"ages: %@", ages);

// print
// ages: (
//     18,
//     22
// )

mutableArrayValueForKey

  1. 使用方法mutableArrayValueForKey:获得persons属性数组:
NASArray *persons = [self mutableArrayValueForKey:@"persons"];

看到这是不是感觉这个方法没啥用,用self.persons也一样可以访问。

  • 但是重点来了:
    比如我们想利用KVO监听数组增删的变化:
[self addObserver:self forKeyPath:@"persons" options:NSKeyValueObservingOptionNew context:nil];

用下面的代码是无法触发的:

[self.persons addObject: [MOPerson personWithName:@"coco"]];

但是用KVC的方法mutableArrayValueForKey:就可以触发KVO:(调用完后persons的地址会发生变化)

[[self mutableArrayValueForKey:@"persons"] addObject:[MOPerson personWithName:@"momo"]];

(麻麻再也不用担心数组变化了,我还不知道了~(•̀ᴗ•́)و ̑̑)

mutableArrayValueForKeyPath

  1. 使用mutableArrayValueForKeyPath:获得persons数组里的所有元素的属性的集合(数组)
NSLog(@"%@", [self mutableArrayValueForKeyPath:@"persons.name"]);
// 输出:
//  (
//      momo,
//      lili
//  )

还有:

  • NSMutableSet的:mutableSetValueForKey:mutableSetValueForKeyPath:
  • NSMutableOrderedSet的:mutableOrderedSetValueForKey:mutableOrderedSetValueForKeyPath:
    同上述NSArray的使用差不多,这里不再累赘了~

三、使用集合运算符

在使用方法valueForKeyPath:时,我们可以在path(键值路径)中嵌入集合运算符,由@xxx表示,在返回集合之前,执行相应的集合运算操作。

  • 集合运算符@xxx之前的部分称为 left key path左键路经,表示需要进行集合运算操作的集合。如果消息的接受者是集合对象(如:NSArray实例),则可以省略左键路经
  • 集合运算符@xxx之后的部分称为 right key path右键路经,表示需要进行操作的属性。
    操作路径格式(Operator key path format) 如下:

Operator key path format
集合运算符表现出三中基本行为类型:

  1. 聚合运算符:Aggregation Operators
  2. 数组运算符:Array Operators
  3. 嵌套运算符:Nesting Operators

下面一一讲解:

1. 聚合运算符:Aggregation Operators

处理 数组 或 一组属性,从而生成一个反应集合某方面的单个值。
如:@avg平均值、@sum求和、@max最大值、@min最小值、@count数量

例:@avg获得集合的平均值:

NSNumber *avgAge = [self.persons valueForKeyPath:@"@avg.age"];

2. 数组运算符:Array Operators

  1. @distinctUnionOfObjects 返回一个数组,枚举出右键路径指定属性所有取值的集合(去重)
NSArray *duNames = [self.persons valueForKeyPath:@"@distinctUnionOfObjects.name"];
//  (
//      lili,
//      momo
//  )
  1. @unionOfObjects 返回一个数组,枚举出右键路径指定属性所有取值的集合 (不去重)
NSArray *unNames = [self.persons valueForKeyPath:@"@unionOfObjects.name"];
//  (
//      momo,
//      lili,
//      momo
//  )

3. 嵌套运算符:Nesting Operators

适用集合中包含集合的情况:

例如,我们给MOPerson类添加一个childens数组:

@property (nonatomic, strong) NSArray <MOPerson*>* childens;
// 初始化:
MOPerson *child1 = [MOPerson personWithName:@"child1"];
MOPerson *child2 = [MOPerson personWithName:@"child2"];

MOPerson *p1 = [MOPerson personWithName:@"momo"];
p1.childens = @[child1, child2];
MOPerson *p2 = [MOPerson personWithName:@"lili"];
p2.childens = @[child2];
self.persons = [@[p1, p2] mutableCopy];
  1. @distinctUnionOfArrays: 把嵌套数组中所有的值全部放到一个数组中 (去重)
NSArray *disChilds = [self.persons valueForKeyPath:@"@distinctUnionOfArrays.childens"];
//  (
//      "<MOPerson: 0x6000013b9c50>", // child1
//      "<MOPerson: 0x6000013b9bf0>", // child2
//  )
  1. @unionOfArrays: 把嵌套数组中所有的值全部放到一个数组中 (不去重)
NSArray *uniChilds = [self.persons valueForKeyPath:@"@unionOfArrays.childens"];
//  (
//      "<MOPerson: 0x6000013b9bf0>", // child1
//      "<MOPerson: 0x6000013b9c50>", // child2
//      "<MOPerson: 0x6000013b9c50>", // child2
//  )

还有@distinctUnionOfSets: @distinctUnionOfArrays类似。因为NSSet本身就不支持重复


三、包装和解包

  1. Wrapping and Unwrapping Scalar Types包装和解包标量类型
    NSNumber的:numberWithBool: 包装bool类型;boolValue: 解包bool类型。
    其他的,如官网中的Table 5-1

  2. Wrapping and Unwrapping Structures 包装和解包结构体类型
    NSPointvalueWithPoint: 包装结构体;pointValue解包结构体
    其他的,如官网中的Table 5-2
    例如:

// 自定义一个结构体
typedef struct {
  float x, y, z;
} ThreeFloats;
// 设置一个属性
@property (nonatomic, assign) ThreeFloats threeFloats;

利用KVC获取属性:

NSValue *threeFloat = [self valueForKey:@"threeFloats"];

利用KVC设置属性:

ThreeFloats floats = {1., 2., 3.};
NSValue *value = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
[self setValue:value forKey:@"threeFloats"];

参考:官网地址
Github上Demo地址

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫小言mo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值