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

2022-07-20 14:17:11 浏览数 (2)

文章目录
  • 一、访问对象属性
    • 1.Getting Attribute 获取属性
    • 2.Setting Attribute 设置属性
  • 二、访问集合属性
    • mutableArrayValueForKey
    • mutableArrayValueForKeyPath
  • 三、使用集合运算符
    • 1. 聚合运算符:`Aggregation Operators`
    • 2. 数组运算符:`Array Operators`
    • 3. 嵌套运算符:`Nesting Operators `
  • 三、包装和解包

例如有这样一个类:

代码语言:javascript复制
@interface MOPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, strong) MOPerson *father;
@end

一、访问对象属性

如有person一个对象:

代码语言:javascript复制
MOPerson *person = [MOPerson personWithName:@"momo"];

1.Getting Attribute 获取属性

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

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

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

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

2.Setting Attribute 设置属性

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

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

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

二、访问集合属性

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

代码语言:javascript复制
@property (nonatomic, strong) NSMutableArray<MOPerson *> *persons;
// 初始化:
MOPerson *p1 = [MOPerson personWithName:@"momo"];
MOPerson *p2 = [MOPerson personWithName:@"lili"];
self.persons = [@[p1, p2] mutableCopy];

mutableArrayValueForKey

  1. 使用方法mutableArrayValueForKey:获得persons属性数组:
代码语言:javascript复制
NASArray *persons = [self mutableArrayValueForKey:@"persons"];

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

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

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

代码语言:javascript复制
[self.persons addObject: [MOPerson personWithName:@"coco"]];

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

代码语言:javascript复制
[[self mutableArrayValueForKey:@"persons"] addObject:[MOPerson personWithName:@"momo"]];

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

mutableArrayValueForKeyPath

  1. 使用mutableArrayValueForKeyPath:获得persons数组里的所有元素的属性的集合(数组)
代码语言:javascript复制
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) 如下:

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

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

下面一一讲解:

1. 聚合运算符:Aggregation Operators

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

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

代码语言:javascript复制
NSNumber *avgAge = [self.persons valueForKeyPath:@"@avg.age"];

2. 数组运算符:Array Operators

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

3. 嵌套运算符:Nesting Operators

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

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

代码语言:javascript复制
@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: 把嵌套数组中所有的值全部放到一个数组中 (去重)
代码语言:javascript复制
NSArray *disChilds = [self.persons valueForKeyPath:@"@distinctUnionOfArrays.childens"];
//  (
//      "<MOPerson: 0x6000013b9c50>", // child1
//      "<MOPerson: 0x6000013b9bf0>", // child2
//  )
  1. @unionOfArrays: 把嵌套数组中所有的值全部放到一个数组中 (不去重)
代码语言:javascript复制
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 例如:
代码语言:javascript复制
// 自定义一个结构体
typedef struct {
  float x, y, z;
} ThreeFloats;
// 设置一个属性
@property (nonatomic, assign) ThreeFloats threeFloats;

利用KVC获取属性:

代码语言:javascript复制
NSValue *threeFloat = [self valueForKey:@"threeFloats"];

利用KVC设置属性:

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

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

0 人点赞