有很多情况,一个属性的值是依赖于其它一个或多个其它对象的属性.如果一个属性的值更改,那么派生属性的值也应该被标记为更改.
对单关系(To-One)
你要重写keyPathsForValuesAffectingValueForKey:
方法
比如:
fullName依赖于firstName和lastName:
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}
当firstName或lastName被改变时,都要通知到那些观察fullName属性的对象.
一种解决办法是重写keyPathsForValuesAffectingValueForKey:
指明fullName属性是依赖于lastName
和firstName
属性的.
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"fullName"]) {
NSArray *affectingKeys = @[@"lastName", @"firstName"];
keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
}
return keyPaths;
}
class override func keyPathsForValuesAffectingValue(forKey key:String) -> Set<String>{
<#Code#>
}
你也可以实现以下的方法来达到相同的目地,用以下的命名格式实现一个类方法keyPathsForValuesAffecting<Key>
,<Key>
是属性的名字(第一个字母要大写).比如:
+ (NSSet *)keyPathsForValuesAffectingFullName {
return [NSSet setWithObjects:@"lastName", @"firstName", nil];
}
当你在category
里增加了一个计算属性时,你不能重写keyPathsForValuesAffectingValueForKey:
方法,因为你不能在category
里重写方法.在这种情况下,你可以用keyPathsForValuesAffecting<Key>
的类方法来实现这个机制(在swift里extension是不是也是这样的情况,有待验证).
对多关系(To-Many)
keyPathsForValuesAffectingValueForKey:
不支持对多关系(Array等).有两种解决办法:
1.你把父注册为所有子的观察者,有一个子类变化了,你就会得到通知:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == totalSalaryContext) {
[self updateTotalSalary];
}
else
// deal with other observations and/or invoke super...
}
- (void)updateTotalSalary {
[self setTotalSalary:[self valueForKeyPath:@"employees.@sum.salary"]];
}
- (void)setTotalSalary:(NSNumber *)newTotalSalary {
if (totalSalary != newTotalSalary) {
[self willChangeValueForKey:@"totalSalary"];
_totalSalary = newTotalSalary;
[self didChangeValueForKey:@"totalSalary"];
}
}
- (NSNumber *)totalSalary {
return _totalSalary;
}
2.如果您使用的是Core Data,则可以将父注册到通知中心作为一个观察者。