美文网首页iOS学习笔记
KVO官方文档学习(四)----注册依赖键

KVO官方文档学习(四)----注册依赖键

作者: 郝嗨森 | 来源:发表于2019-01-28 14:18 被阅读1次

官方文档

There are many situations in which the value of one property depends on that of one or more other attributes in another object. If the value of one attribute changes, then the value of the derived property should also be flagged for change. How you ensure that key-value observing notifications are posted for these dependent properties depends on the cardinality of the relationship.

很多种情况一个属性的值依赖于另一个对象的一个或更多其他属性。如果一个属性的值改变了,这个派生的属性的值也应该被标记为改变。如何确保这些为这些依赖属性发送KVO通知取决于关系的基数。

一对一关系(To-One Relationships)

To trigger notifications automatically for a to-one relationship you should either override keyPathsForValuesAffectingValueForKey: or implement a suitable method that follows the pattern it defines for registering dependent keys.

为了自动触发一对一关系的通知,应该重写keyPathsForValuesAffectingValueForKey:或者实现一个合适的方法遵循为注册依赖键而定义的模式。

For example, the full name of a person is dependent on both the first and last names. A method that returns the full name could be written as follows:

例如,一个人的姓名依赖于姓和名。一个返回姓名的方法可以写成以下这样:

- (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}

An application observing the fullName property must be notified when either the firstName or lastName properties change, as they affect the value of the property.

一个观察fullName属性的应用程序当firstName或者lastName属性改变的时候应该被通知,因为它们影响这个属性的值。

One solution is to override keyPathsForValuesAffectingValueForKey: specifying that the fullName property of a person is dependent on the lastName and firstName properties. Listing 1 shows an example implementation of such a dependency:

一中方法时重写keyPathsForValuesAffectingValueForKey:,指定person的fullName 属性依赖于lastName and firstName属性。Listing 1展示了这种以来的实现:

Listing 1  Example implementation of keyPathsForValuesAffectingValueForKey:


+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
 
    if ([key isEqualToString:@"fullName"]) {
        NSArray *affectingKeys = @[@"lastName", @"firstName"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

Your override should typically invoke super and return a set that includes any members in the set that result from doing that (so as not to interfere with overrides of this method in superclasses).

重写方法通常应该调用父类并且返回一个集合,这个集合包括导致这样做的集合中的任何成员。(以免干扰到父类中这个方法的实现)

You can also achieve the same result by implementing a class method that follows the naming convention keyPathsForValuesAffecting<Key>, where <Key> is the name of the attribute (first letter capitalized) that is dependent on the values. Using this pattern the code in Listing 1 could be rewritten as a class method named keyPathsForValuesAffectingFullName as shown in Listing 2.

你也可以通过实现一个遵循keyPathsForValuesAffecting<Key>命名约定的类方法来实现相同的结果, <Key> 是依赖于值的属性(首字母大写)。使用这种模式Listing 1中的代码可以被重写为Listing 2中所示的类方法keyPathsForValuesAffectingFullName

Listing 2  Example implementation of the keyPathsForValuesAffecting<Key> naming convention

+ (NSSet *)keyPathsForValuesAffectingFullName {
    return [NSSet setWithObjects:@"lastName", @"firstName", nil];
}

You can't override the keyPathsForValuesAffectingValueForKey: method when you add a computed property to an existing class using a category, because you're not supposed to override methods in categories. In that case, implement a matching keyPathsForValuesAffecting<Key> class method to take advantage of this mechanism.

当你使用类别给一个已经存在的类添加一个计算过的属性时,不能重写keyPathsForValuesAffectingValueForKey:方法,因为你不应该在分类中重写方法。在这种情况下,实现匹配的类方法keyPathsForValuesAffecting<Key>来利用这种机制。

Note: You cannot set up dependencies on to-many relationships by implementing keyPathsForValuesAffectingValueForKey:. Instead, you must observe the appropriate attribute of each of the objects in the to-many collection and respond to changes in their values by updating the dependent key yourself. The following section shows a strategy for dealing with this situation.

注意:不可以通过实现keyPathsForValuesAffectingValueForKey:为一对多关系设置依赖。相反,你必须观察一对多集合中每个对象的响应属性,并通过自己更新依赖键来响应其值的改变。以下部分显示了处理这种情况的策略。

一对多关系(To-Many Relationships)

The keyPathsForValuesAffectingValueForKey: method does not support key-paths that include a to-many relationship. For example, suppose you have a Department object with a to-many relationship (employees) to a Employee, and Employee has a salary attribute. You might want the Department object have a totalSalary attribute that is dependent upon the salaries of all the Employees in the relationship. You can not do this with, for example, keyPathsForValuesAffectingTotalSalary and returning employees.salary as a key.

keyPathsForValuesAffectingValueForKey:方法不支持包含一对多关系的key-path。例如,假设有一个Department对象和Employee有这一对多的关系,而且Employee有个salary属性。你可能想要Department对象有一个totalSalary属性依赖于关系中的所有Employees的salaries。你不能使用keyPathsForValuesAffectingTotalSalary并且把employees.salary当做一个键来返回。

There are two possible solutions in both situations:
1.You can use key-value observing to register the parent (in this example, Department) as an observer of the relevant attribute of all the children (Employees in this example). You must add and remove the parent as an observer as child objects are added to and removed from the relationship (see Registering for Key-Value Observing). In the observeValueForKeyPath:ofObject:change:context: method you update the dependent value in response to changes, as illustrated in the following code fragment:

在这两种情况下有两种可能的解决方案:
1.你可以使用KVO来注册父类(Department)作为所有子类(Employees)相关属性的观察者。你必须在对象关系中添加和删除子类对象时添加和移除父类作为观察者。在observeValueForKeyPath:ofObject:change:context:方法中更新依赖的值来响应改变,如以下代码片段所示:

- (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.If you're using Core Data, you can register the parent with the application's notification center as an observer of its managed object context. The parent should respond to relevant change notifications posted by the children in a manner similar to that for key-value observing.

如果你在使用Core Data,你可以使用应用程序的通知中心来注册父类成为它管理的对象上下文的观察者。父类应该以类似于KVO的形式来响应子类发出的相关的改变通知。

相关文章

网友评论

    本文标题:KVO官方文档学习(四)----注册依赖键

    本文链接:https://www.haomeiwen.com/subject/urnojqtx.html