文章目录- 一、访问对象属性
- 1.Getting Attribute 获取属性
- 2.Setting Attribute 设置属性
- 二、访问集合属性
- mutableArrayValueForKey
- mutableArrayValueForKeyPath
- 三、使用集合运算符
- 1. 聚合运算符:`Aggregation Operators`
- 2. 数组运算符:`Array Operators`
- 3. 嵌套运算符:`Nesting Operators `
- 三、包装和解包
- 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 获取属性
- 使用方法
valueForKey:
获取对象的属性
[person valueForKey:@"name"];
- 使用方法
valueForKeyPath:
可以访问属性的属性,采用点语法
[person valueForKeyPath:@"father.name"];
以上2个方法如果Key
值不对(即该属性不存在),则会触发valueForUndefinedKey:
方法,默认会抛出NSUndefinedKeyException
异常,导致crash。
- 我们也可以重写该类的此方法,打印出log,避免crash:
- (id)valueForUndefinedKey:(NSString *)key {
NSLog(@"Error: valueForUndefinedKey: %@", key);
return nil;
}
- 使用方法
dictionaryWithValuesForKeys:
返回一个字典包含,给出的keys的values
NSDictionary *dic = [person dictionaryWithValuesForKeys:@[@"name", @"age"]];
NSLog(@"%@", dic);
// 输出:
// age = "<null>";
// name = lili;
注意:这里没有的key
(属性),也会返回一个"<null>"
2.Setting Attribute 设置属性
- 使用方法
setValue:forKey:
修改对象的属性
[person setValue:@"miki" forKey:@"name"];
- 使用方法
setValue:forKeyPath:
修改对象的属性的属性,采用点语法
[person setValue:@"baba" forKeyPath:@"father.name"];
- 使用方法
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 数组
代码语言:javascript复制@property (nonatomic, strong) NSMutableArray<MOPerson *> *persons;
// 初始化:
MOPerson *p1 = [MOPerson personWithName:@"momo"];
MOPerson *p2 = [MOPerson personWithName:@"lili"];
self.persons = [@[p1, p2] mutableCopy];
mutableArrayValueForKey
- 使用方法
mutableArrayValueForKey:
获得persons属性数组:
NASArray *persons = [self mutableArrayValueForKey:@"persons"];
看到这是不是感觉这个方法没啥用,用self.persons
也一样可以访问。
- 但是重点来了: 比如我们想利用KVO监听数组增删的变化:
[self addObserver:self forKeyPath:@"persons" options:NSKeyValueObservingOptionNew context:nil];
用下面的代码是无法触发的:
代码语言:javascript复制[self.persons addObject: [MOPerson personWithName:@"coco"]];
但是用KVC的方法mutableArrayValueForKey:
就可以触发KVO:(调用完后persons的地址会发生变化)
[[self mutableArrayValueForKey:@"persons"] addObject:[MOPerson personWithName:@"momo"]];
(麻麻再也不用担心数组变化了,我还不知道了~(•̀ᴗ•́)و ̑̑)
mutableArrayValueForKeyPath
- 使用
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
) 如下:
集合运算符表现出三中基本行为类型:
- 聚合运算符:
Aggregation Operators
- 数组运算符:
Array Operators
- 嵌套运算符:
Nesting Operators
下面一一讲解:
1. 聚合运算符:Aggregation Operators
处理 数组 或 一组属性,从而生成一个反应集合某方面的单个值。
如:@avg
平均值、@sum
求和、@max
最大值、@min
最小值、@count
数量
例:@avg
获得集合的平均值:
NSNumber *avgAge = [self.persons valueForKeyPath:@"@avg.age"];
2. 数组运算符:Array Operators
@distinctUnionOfObjects
返回一个数组,枚举出右键路径
指定属性所有取值的集合(去重)
NSArray *duNames = [self.persons valueForKeyPath:@"@distinctUnionOfObjects.name"];
// (
// lili,
// momo
// )
@unionOfObjects
返回一个数组,枚举出右键路径
指定属性所有取值的集合 (不去重)
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];
@distinctUnionOfArrays:
把嵌套数组中所有的值全部放到一个数组中 (去重)
NSArray *disChilds = [self.persons valueForKeyPath:@"@distinctUnionOfArrays.childens"];
// (
// "<MOPerson: 0x6000013b9c50>", // child1
// "<MOPerson: 0x6000013b9bf0>", // child2
// )
@unionOfArrays:
把嵌套数组中所有的值全部放到一个数组中 (不去重)
NSArray *uniChilds = [self.persons valueForKeyPath:@"@unionOfArrays.childens"];
// (
// "<MOPerson: 0x6000013b9bf0>", // child1
// "<MOPerson: 0x6000013b9c50>", // child2
// "<MOPerson: 0x6000013b9c50>", // child2
// )
还有@distinctUnionOfSets:
和@distinctUnionOfArrays
类似。因为NSSet
本身就不支持重复
三、包装和解包
-
Wrapping and Unwrapping Scalar Types
包装和解包标量类型 如NSNumber
的:numberWithBool:
包装bool类型;boolValue:
解包bool类型。 其他的,如官网中的Table 5-1 -
Wrapping and Unwrapping Structures
包装和解包结构体类型 如NSPoint
的valueWithPoint:
包装结构体;pointValue
解包结构体 其他的,如官网中的Table 5-2 例如:
// 自定义一个结构体
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地址