你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> KVO編程指南,Key-Value Observing Programming Guide翻譯 - iOS

KVO編程指南,Key-Value Observing Programming Guide翻譯 - iOS

編輯:IOS開發綜合

1 Introduction to Key-Value Observing Programming Guide - KVO編程指南介紹

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects.

鍵 - 值觀察是一種機制,當指定對象屬性改變的時候允許另一個對象接受通知。

Important: In order to understand key-value observing, you must first understand key-value coding.

重要:了解鍵值觀察之前,首先要理解鍵值編程 (key-value coding)

1.1 At a Glance - 概括

Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application. (In OS X, the controller layer binding technology relies heavily on key-value observing.) A controller object typically observes properties of model objects, and a view object observes properties of model objects through a controller. In addition, however, a model object may observe other model objects (usually to determine when a dependent value changes) or even itself (again to determine when a dependent value changes).

You can observe properties including simple attributes, to-one relationships, and to-many relationships. Observers of to-many relationships are informed of the type of change made—as well as which objects are involved in the change.

There are three steps to setting up an observer of a property. Understanding these three steps provides a clear illustration of how KVO works.

鍵 - 值觀察是一種機制,當指定對象屬性改變的時候允許另一個對象接受通知。在應用中,對於模型和控制器層之間的交流非常有用。(在 OS X 中,控制器層綁定技術嚴重依賴於鍵-值觀察。)一個控制器對象通常觀察模型對象的屬性,視圖對象通過控制器觀察模型對象的屬性。然後,一個模型對象可以觀察其它模型對象(通常為了確定從屬值是什麼時候改變的),或者甚至觀察自身(也是為了確定從屬值何時變化)。

你可以觀察一些屬性,比如簡單的屬性,一對一關系的,一對多關系的。一對多關系的觀察者可以收到變化的類型,以及哪些對象發生了改變。

建立屬性的觀察者有三步。下面提供一個清晰的KVO工作方式演示,來理解這三步。

1.First, see whether you have a scenario where key-value observing could be beneficial, for example, an object that needs to be notified when any changes are made to a specific property in another object.

1.首先,考慮這樣的一個場景,例如當對一個A對象的特定做出任何改變的時候,B對象需要被通知。

 


\

 <喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjIuVGhlIFBlcnNvbk9iamVjdCBtdXN0IHJlZ2lzdGVyIGFzIGFuIG9ic2VydmVyIG9mIHRoZSBCYW5rT2JqZWN0JnJzcXVvO3MgYWNjb3VudEJhbGFuY2UgcHJvcGVydHkgYnkgc2VuZGluZyBhbiBhZGRPYnNlcnZlcjpmb3JLZXlQYXRoOm9wdGlvbnM6Y29udGV4dDogbWVzc2FnZS48L3A+DQo8cD4yLlBlcnNvbk9iamVjdLHY0OvXorLhzqogQmFua09iamVjdCC1xCBhY2NvdW50QmFsYW5jZSDK9NDUtcS527Ls1d+jrM2ouf23osvN0ru49s/7z6IgPGEgaHJlZj0="https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/index.html">addObserver:forKeyPath:options:context:

 


\

 

Note: The addObserver:forKeyPath:options:context: method establishes a connection between the instances of the objects that you specify. A connection is not established between the two classes, but rather between the two specified instances of the objects.

注意:addObserver:forKeyPath:options:context: 方法規定了一個指定對象實例之間的連接。注意不是兩個類之間的連接,兩個對象的實例。

3.In order to respond to change notifications, the observer must implement the observeValueForKeyPath:ofObject:change:context: method. This method implementation defines how the observer responds to change notifications. It is in this method that you can customize your response to a change in one of the observed properties.

3.為了響應變化的通知,觀察者必須實現方法 observeValueForKeyPath:ofObject:change:context:。這個方法的實現中定義了觀察者如何響應改變通知。可以在這個方法中定制被觀察屬性之一改變時的響應。

 


\

 

Registering for Key-Value Observing describes how to register and receive observation notifications.

Registering for Key-Value Observing說明如何注冊和接受觀察的通知。

4.The observeValueForKeyPath:ofObject:change:context: method is automatically invoked when the value of an observed property is changed in a KVO-compliant manner, or if a key upon which it depends is changed.

4.當被觀察屬性的值在KVO-compliant方式中改變 或者它依賴的一個key改變的時候,observeValueForKeyPath:ofObject:change:context: 方法自動被調用。

 


\

 

Registering Dependent Keys explains how to specify that the value of a key is dependent on the value of another key.

Registering Dependent Keys 解釋了指定一個鍵的值依賴於另一個鍵的值。

KVO’s primary benefit is that you don’t have to implement your own scheme to send notifications every time a property changes. Its well-defined infrastructure has framework-level support that makes it easy to adopt—typically you do not have to add any code to your project. In addition, the infrastructure is already full-featured, which makes it easy to support multiple observers for a single property, as well as dependent values.

KVO Compliance describes the difference between automatic and manual key-value observing, and how to implement both.

Unlike notifications that use NSNotificationCenter, there is no central object that provides change notification for all observers. Instead, notifications are sent directly to the observing objects when changes are made. NSObject provides this base implementation of key-value observing, and you should rarely need to override these methods.

Key-Value Observing Implementation Details describes how key-value observing is implemented.

KVO的優點是,每次屬性改變的時候,不需要自己實現發送通知。它良好定義的基礎設施有架構層面的支持,使得它易於使用,通常不需要再工程中添加任何代碼。此外,基礎設施已經是全特性的,它可以很容易地支持單一屬性的多個觀察者,以及相關的值。

KVO Compliance 描述了自動和手動鍵值觀察的區別,以及如何實現兩者。

於使用 NSNotificationCenter 的通知不同,這裡沒有為所有觀察者提供更改通知的中央對象,。相反,更改時通知直接被發送到觀察對象。NSObject 提供了鍵值觀察的基本實現,你應該很少需要重寫這些方法。

Key-Value Observing Implementation Details描述鍵值觀察室如何實現的。

2 Registering for Key-Value Observing - 注冊鍵值觀察

In order to receive key-value observing notifications for a property, three things are required:

The observed class must be key-value observing compliant for the property that you wish to observe. You must register the observing object with the observed object, using the method addObserver:forKeyPath:options:context:. The observing class must implement observeValueForKeyPath:ofObject:change:context:.

針對一個屬性,為了接收鍵值觀察通知,有3個要求:

對於你希望觀察的屬性,被觀察的類必須是鍵值觀察兼容的。 你必須對被觀察的對象注冊觀察對象,使用方法 addObserver:forKeyPath:options:context: 觀察類必須實現方法 observeValueForKeyPath:ofObject:change:context:

Important: Not all classes are KVO-compliant for all properties. You can ensure your own classes are KVO-compliant by following the steps described in KVO Compliance. Typically properties in Apple-supplied frameworks are only KVO-compliant if they are documented as such.

重要提示:不是所有類對於所有屬性都是KVO兼容的。你可以通過下面幾個步驟確保你自己的類是KVO兼容的,在KVO Compliance中有描述。通常,如果它們被記錄為這種蘋果提供的框架屬性,那就唯一KVO兼容的。

2.1 Registering as an Observer - 注冊為一個觀察者

In order to be notified of changes to a property, an observing object must first register with the object to be observed by sending it an addObserver:forKeyPath:options:context: message, passing the observer object and the key path of the property to be observed. The options parameter specifies the information that is provided to the observer when a change notification is sent. Using the option NSKeyValueObservingOptionOld specifies that the original object value is provided to the observer as an entry in the change dictionary. Specifying the NSKeyValueObservingOptionNew option provides the new value as an entry in the change dictionary. To receive both values, you would bitwise OR the option constants.

The example in Listing 1 demonstrates registering an inspector object for the property openingBalance.

為了屬性改變時能被通知到,觀察對象首先要對被觀察對象進行注冊,通過給被觀察對象發送消息 addObserver:forKeyPath:options:context: 。傳給的參數是觀察者對象,被觀察對象屬性的鍵路徑(key path)。可選的參數是當改變通知被發送的時候,提供給觀察者的指定信息。使用選項 NSKeyValueObservingOptionOld 指定原始對象的值,在變化字典中提供給觀察者。NSKeyValueObservingOptionNew 選項,提供新的值。為了收到這兩個值,你應該對這兩個選項常量使用位或。

清單1的例子演示給 openingBalance 屬性注冊一個觀察者 inspector 對象。

- (void)registerAsObserver {
    /*
     注冊 `inspector` ,來接收 `account` 對象的屬性 `openingBalance` 
     改變時的通知,並且指定舊值和新值都應該提供給觀察者。
     */
    [account addObserver:inspector
             forKeyPath:@"openingBalance"
                 options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                    context:NULL];
}

When you register an object as an observer, you can also provide a context pointer. The context pointer is provided to the observer when observeValueForKeyPath:ofObject:change:context: is invoked. The context pointer can be a C pointer or an object reference. The context pointer can be used as a unique identifier to determine the change that is being observed, or to provide some other data to the observer.

Note: The key-value observing addObserver:forKeyPath:options:context: method does not maintain strong references to the observing object, the observed objects, or the context. You should ensure that you maintain strong references to the observing, and observed, objects, and the context as necessary.

注冊的時候,也可以提供一個上下文指針(context pointer),當 observeValueForKeyPath:ofObject:change:context: 被調用的時候,context pointer 會被提供給觀察者。context pointer 可以是一個 C pointer 或者 一個對象引用。context pointer 可以用作唯一標識符,來確定正在被觀察對象的變化,或者提供某些其他數據給觀察者。

注意:鍵值觀察方法 addObserver:forKeyPath:options:context: ,對於觀察者對象,被觀察的對象或者 context 都不會維持強引用。在必要的時候,你應該自己確保你對於它們維持強引用。

2.2 Receiving Notification of a Change - 針對改變接收通知

When the value of an observed property of an object changes, the observer receives an observeValueForKeyPath:ofObject:change:context: message. All observers must implement this method.

The observer is provided the object and key path that triggered the observer notification, a dictionary containing details about the change, and the context pointer that was provided when the observer was registered.

The change dictionary entry NSKeyValueChangeKindKey provides information about the type of change that occurred. If the value of the observed object has changed, the NSKeyValueChangeKindKey entry returns NSKeyValueChangeSetting. Depending on the options specified when the observer was registered, the NSKeyValueChangeOldKey and NSKeyValueChangeNewKey entries in the change dictionary contain the values of the property before, and after, the change. If the property is an object, the value is provided directly. If the property is a scalar or a C structure, the value is wrapped in an NSValue object (as with key-value coding).

If the observed property is a to-many relationship, the NSKeyValueChangeKindKey entry also indicates whether objects in the relationship were inserted, removed, or replaced by returning NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, or NSKeyValueChangeReplacement, respectively.

The change dictionary entry for NSKeyValueChangeIndexesKey is an NSIndexSet object specifying the indexes in the relationship that changed. If NSKeyValueObservingOptionNew or NSKeyValueObservingOptionOld are specified as options when the observer is registered, the NSKeyValueChangeOldKey and NSKeyValueChangeNewKey entries in the change dictionary are arrays containing the values of the related objects before, and after, the change.

The example in Listing 2 shows the observeValueForKeyPath:ofObject:change:context: implementation for an inspector that reflects the old and new values of the property openingBalance, as registered in Listing 1.

當一個改變了被觀察對象屬性的值,觀察者收到消息 observeValueForKeyPath:ofObject:change:context: 。所有的觀察者必須實現這個方法。

觀察者被提供 觸發觀察者通知的對象和 key path ,就是一個字典,包含了變化和注冊時填寫的context pointer。

變化字典中 NSKeyValueChangeKindKey 提供了關於發生變化的信息。如果被觀察對象的值被改變了,NSKeyValueChangeKindKey 返回 NSKeyValueChangeSetting 。根據觀察者被注冊時指定的選項,NSKeyValueChangeOldKey 和 NSKeyValueChangeNewKey ,在變化字典中包含了屬性之前的值以及改變之後的值。如果屬性是一個對象,值會被直接提供。如果屬性是標量或者C結構體,值會被包含在一個 NSValue 對象中(比如 鍵值編程)。

如果被觀察的屬性是一對多的關系(比如數組,集合),NSKeyValueChangeKindKey 也會指定關系中的對象是否被返回的 NSKeyValueChangeInsertion 插入,NSKeyValueChangeRemoval 移除或者 NSKeyValueChangeReplacement 替代。

變化字典的條目 NSKeyValueChangeIndexesKey 是一個 NSIndexSet 對象,指出被改變關系的下標。如果注冊的時候 NSKeyValueObservingOptionNew 或者 NSKeyValueObservingOptionOld 被指定為選項,變化字典中 NSKeyValueChangeOldKey 和 NSKeyValueChangeNewKey 就會是數組,包含了相關對象變化之前和之後的值。

清單2的例子演示了 observeValueForKeyPath:ofObject:change:context: 實現

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if ([keyPath isEqual:@"openingBalance"]) {
        [openingBalanceInspectorField setObjectValue:
            [change objectForKey:NSKeyValueChangeNewKey]];
    }
    /*
     Be sure to call the superclass's implementation *if it implements it*.
     NSObject does not implement the method.
     */
    [super observeValueForKeyPath:keyPath
                         ofObject:object
                           change:change
                           context:context];
}

2.3 Removing an Object as an Observer 移除對象觀察者

You remove a key-value observer by sending the observed object a removeObserver:forKeyPath: message, specifying the observing object and the key path. The example in Listing 3 removes the inspector as an observer of openingBalance.

你可以給被觀察對象發送一個消息 removeObserver:forKeyPath: 來移除鍵值觀察,指定觀察者對象和 key path 。清單3 的例子移除了 openingBalance 的觀察者 inspector 。

- (void)unregisterForChangeNotification {
    [observedObject removeObserver:inspector forKeyPath:@"openingBalance"];
}

If the context is an object, you must keep a strong reference to it until removing the observer. After receiving a removeObserver:forKeyPath: message, the observing object will no longer receive any observeValueForKeyPath:ofObject:change:context: messages for the specified key path and object.

如果 context 是一個對象,在移除觀察者之前你必須對它保持一個強引用。接收到 removeObserver:forKeyPath: 消息後,觀察對象將不在接收任何指定 key path 和對象的 observeValueForKeyPath:ofObject:change:context: 消息。

3 KVO Compliance - KVO 兼容性

In order to be considered KVO-compliant for a specific property, a class must ensure the following:

The class must be key-value coding compliant for the property, as specified in Ensuring KVC Compliance. KVO supports the same data types as KVC. The class emits KVO change notifications for the property. Dependent keys are registered appropriately (see Registering Dependent Keys).

There are two techniques for ensuring the change notifications are emitted. Automatic support is provided by NSObject and is by default available for all properties of a class that are key-value coding compliant. Typically, if you follow standard Cocoa coding and naming conventions, you can use automatic change notifications—you don’t have to write any additional code.

Manual change notification provides additional control over when notifications are emitted, and requires additional coding. You can control automatic notifications for properties of your subclass by implementing the class method automaticallyNotifiesObserversForKey:.

考慮到指定屬性的 KVO-compliant,類必須確認下面幾點:

類對於屬性必須被鍵值編程兼容,在 Ensuring KVC Compliance 中有指出。KVO支持與KVC相同的數據類型。 類對於屬性能發出KVO改變通知。 在注冊時適當的設置相關的 key (見 Registering Dependent Keys)

有兩種技術確保改變通知被發出。自動支持由 NSObject 提供,並且對於一個類的所有屬性鍵值編程兼容性都是可用的。通常來說,如果遵循標准的Cocoa 編程和命名規范,你就可以使用自動變化通知,不用寫任何額外的代碼。

手動變化通知在當通知被發出的時候提供了額外的控制,並且需要添加一些代碼。你可以通過實現類方法 automaticallyNotifiesObserversForKey: 來控制你子類屬性的自動通知。

3.1 Automatic Change Notification - 自動變化通知

NSObject provides a basic implementation of automatic key-value change notification. Automatic key-value change notification informs observers of changes made using key-value compliant accessors, as well as the key-value coding methods. Automatic notification is also supported by the collection proxy objects returned by, for example, mutableArrayValueForKey:.

The examples shown in Listing 1 result in any observers of the property name to be notified of the change.

Listing 1 Examples of method calls that cause KVO change notifications to be emitted

NSObject 提供了一個自動鍵值變化通知的基本實現。自動鍵值變化通知告知所做改變的觀察者使用鍵值兼容的 accessors,以及鍵值編程方法。自動通知也被返回的集合代理對象支持,例如 mutableArrayValueForKey:。

清單1的例子展示了改變時,屬性名被修改的情況下任何觀察者的結果。

清單1,導致發出KVO變化通知的方法調用例子

// Call the accessor method.
[account setName:@"Savings"];

// Use setValue:forKey:.
[account setValue:@"Savings" forKey:@"name"];

// Use a key path, where 'account' is a kvc-compliant property of 'document'.
[document setValue:@"Savings" forKeyPath:@"account.name"];

// Use mutableArrayValueForKey: to retrieve a relationship proxy object.
Transaction *newTransaction = <#Create a new transaction for the account#>;
NSMutableArray *transactions = [account mutableArrayValueForKey:@"transactions"];
[transactions addObject:newTransaction];

3.2 Manual Change Notification - 手動變化通知

Manual change notification provides more granular control over how and when notifications are sent to observers. This can be useful to help minimize triggering notifications that are unnecessary, or to group a number of changes into a single notification.

A class that implements manual notification must override the NSObject implementation of automaticallyNotifiesObserversForKey:. It is possible to use both automatic and manual observer notifications in the same class. For properties that perform manual notification, the subclass implementation of automaticallyNotifiesObserversForKey: should return NO. A subclass implementation should invoke super for any unrecognized keys. The example in Listing 2 enables manual notification for the openingBalance property allowing the superclass to determine the notification for all other keys.

Listing 2 Example implementation of automaticallyNotifiesObserversForKey:

手動變化通知在當通知被發送給觀察者的時候提供了更多精細的控制。對於減少不必要的觸發通知,或者一大波變化給一個通知,都很有幫助。

實現手動通知的類必須重寫 NSObject 實現的方法 automaticallyNotifiesObserversForKey: 。有可能在相同的類中使用自動和手動的觀察通知。對於執行手動通知的屬性,子類的 automaticallyNotifiesObserversForKey: 方法實現應該返回 NO。子類實現中對於任何為確認的 key,應該調用父類。清單2的例子對於 openingBalance 屬性啟用了手動通知,允許父類來決定所有其他 key 的通知。

清單2 automaticallyNotifiesObserversForKey:實現的例子

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {

    BOOL automatic = NO;
    if ([theKey isEqualToString:@"openingBalance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

To implement manual observer notification, you invoke willChangeValueForKey: before changing the value, and didChangeValueForKey: after changing the value. The example in Listing 3 implements manual notifications for the openingBalance property.

Listing 3 Example accessor method implementing manual notification

要實現手動觀察通知,在值變化之前要調用 willChangeValueForKey:,值變化之後要調用 didChangeValueForKey: 。清單3的例子,對於 openingBalance 屬性實現了手動通知。

清單3 accessor 方法實現手動通知的例子

- (void)setOpeningBalance:(double)theBalance {
    [self willChangeValueForKey:@"openingBalance"];
    _openingBalance = theBalance;
    [self didChangeValueForKey:@"openingBalance"];
}

You can minimize sending unnecessary notifications by first checking if the value has changed. The example in Listing 4 tests the value of openingBalance and only provides the notification if it has changed.

Listing 4 Testing the value for change before providing notification

你可以先檢查值是否改變,來將不必要發送的通知最小化。清單3的例子測試了 openingBalance 的值,並且只提供了如果它改變的通知。

清單4 在通知之前測試值得變化

- (void)setOpeningBalance:(double)theBalance {
    if (theBalance != _openingBalance) {
        [self willChangeValueForKey:@"openingBalance"];
        _openingBalance = theBalance;
        [self didChangeValueForKey:@"openingBalance"];
    }
}

If a single operation causes multiple keys to change you must nest the change notifications as shown in Listing 5.

Listing 5 Nesting change notifications for multiple keys

如果一個操作導致多個 key 的變化,你必須像清單5 一樣將變化通知進行嵌套。

清單5 對多個 key 將變化通知嵌套

- (void)setOpeningBalance:(double)theBalance {
    [self willChangeValueForKey:@"openingBalance"];
    [self willChangeValueForKey:@"itemChanged"];
    _openingBalance = theBalance;
    _itemChanged = _itemChanged+1;
    [self didChangeValueForKey:@"itemChanged"];
    [self didChangeValueForKey:@"openingBalance"];
}

In the case of an ordered to-many relationship, you must specify not only the key that changed, but also the type of change and the indexes of the objects involved. The type of change is an NSKeyValueChange that specifies NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, or NSKeyValueChangeReplacement. The indexes of the affected objects are passed as an NSIndexSet object.

The code fragment in Listing 6 demonstrates how to wrap a deletion of objects in the to-many relationship transactions.

Listing 6 Implementation of manual observer notification in a to-many relationship

在有序,一對多關系的情況下,你必須指出不僅 key 發生了變化,還要指出變化的類型以及被調用對象的下標。變換的類型是 NSKeyValueChange ,可以指定 NSKeyValueChangeInsertion,NSKeyValueChangeRemoval或者 NSKeyValueChangeReplacement 。受影響對象的索引作為 NSIndexSet 對象被傳遞。

清單6 一對多關系的手動觀察通知的實現

- (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes {
    [self willChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];

    // Remove the transaction objects at the specified indexes.

    [self didChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];
}

4 Registering Dependent Keys - 注冊相關 key

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.

一個屬性的值取決於一個或者多個其他對象的屬性,有很多種情況。如果一個屬性變化,那麼派生屬性也應該被標記改變。對於這些相關屬性依賴於關系的基數,你如果確保通知被發出。

4.1 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.

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:

對於一對一關系,為了自動觸發通知,你應該重寫 keyPathsForValuesAffectingValueForKey: 方法,或者實現一個合適的方法,遵循一種模式,它定義取決於注冊相關的key。

例如,一個人的全名依賴於人的姓和名。一個返回全名的方法可以寫成下面形式:

- (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.

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:

Listing 1 Example implementation of keyPathsForValuesAffectingValueForKey:

應用觀察 fullName 屬性,必須注意到當 firstName 或者 lastName 屬性變化時,會影響到 fullName屬性的值。

一種解決方法是重寫 keyPathsForValuesAffectingValueForKey: ,指定人的 fullName 屬性依賴於 lastName 和 firstName 屬性。清單1 展示了這樣一個例子:

清單1 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, where 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.

Listing 2 Example implementation of the keyPathsForValuesAffecting naming convention

重寫,通常應該調用 super ,並且返回一個 set ,包括這樣做的導致結果的任何成員。(在父類中不要因為這個方法的重寫造成干擾)。

你也可以通過實現一個類方法達到同樣的結果,遵循命名約定 keyPathsForValuesAffecting, 是屬性名(首字母大寫),依賴於值。清單1中使用這種模式的代碼,可以像在清單2中被重寫為一個類方法 keyPathsForValuesAffectingFullName 。

清單2 keyPathsForValuesAffecting 命名約定的實現例子

+ (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 class method to take advantage of this mechanism.

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.

當你使用一個 category 給一個現有的類添加一個計算屬性的時候,你不能重寫 keyPathsForValuesAffectingValueForKey: 方法,因為不允許重寫分類(categories)中的方法。這種情況下,實現一個匹配的 keyPathsForValuesAffecting 類方法,體現了這種機制的優勢。

注意:你不能通過實現 keyPathsForValuesAffectingValueForKey: 方法建立依賴於一對多的關系。相反,你必須觀察一對多集合中對象的每個響應屬性,並通過更新自己依賴的 key 來響應它們值的變化。下面一節講了處理這種情況的一種策略。

4.2 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.

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:

keyPathsForValuesAffectingValueForKey: 方法不支持包含一對多關系的 key-path。例如,Department 對象有一個一對多的關系 對於 Employee,Employee 有 salary 屬性。你希望 Department 對象有一個 totalSalary 屬性,這個屬性依賴於所有 Employees。你不能像下面這樣,keyPathsForValuesAffectingTotalSalary 並且將 employees.salary 作為一個 key 返回。

在兩種情況中有兩個可能的解決方法:

1.可以使用鍵值觀察注冊 parent(例子中就是 Department) 作為所有 children(Employees) 相關屬性的觀察者。你必須添加和移除 parent 。在 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:@"[email protected]"]];
}

- (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.

2.如果使用Core Data,你可以在應用程序的通知中心注冊 parent 作為它管理的對象 context 的觀察者。parent 應該響應 與鍵值觀察類似方式被 children 發出的的變化通知。

4.3 Key-Value Observing Implementation Details - 鍵值觀察實現細節

Automatic key-value observing is implemented using a technique called isa-swizzling.

The isa pointer, as the name suggests, points to the object’s class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.

When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

自動鍵值觀察是使用一種稱為 isa-swizzling 的技術實現。

isa 指針,顧名思義,只想一個對象的類,維持一個調度表。這個調度表基本上包含指向類的方法實現以及其他數據的指針。

當一個觀察者被注冊,被觀察者對象的 isa 指針所指的對象的屬性被修改,指的是一個中間的類而不是真正的類。結果就是 isa 指針的值並不一定反映實際類的實例。

你應該永遠不要依靠 isa 指針來確定類成員資格。相反,你應該使用 class 方法來確定對象實例的類。

蘋果官方文檔地址:Key-Value Observing Programming Guide

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved