你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS KVO 鍵值察看

iOS KVO 鍵值察看

編輯:IOS開發綜合

察看 model 對象的變化

在 Cocoa 的模型-視圖-控制器 (Model-view-controller)架構裡,控制器擔任讓視圖和模型同步。這一共有兩步:當 model 對象改動的時分,視圖應該隨之改動以反映模型的變化;當用戶和控制器交互的時分,模型也應該做出相應的改動。

KVO 能協助我們讓視圖和模型堅持同步。控制器可以察看視圖依賴的屬性變化。

讓我們看一個例子:我們的模型類 LabColor 代表一種 Lab顏色空間裡的顏色。和 RGB 不同,這種顏色空間有三個元素 L, a, b。我們要做一個用來改動這些值的滑塊和一個顯示顏色的方塊區域。

我們的模型類有以下三個用來代表顏色的屬性:

@property (nonatomic) double lComponent;
@property (nonatomic) double aComponent;
@property (nonatomic) double bComponent;

依賴的屬性
我們需求從這個類創立一個 UIColor 對象來顯示出顏色。我們添加三個額定的屬性,辨別對應 R, G, B:

@property (nonatomic, readonly) double redComponent;
@property (nonatomic, readonly) double greenComponent;
@property (nonatomic, readonly) double blueComponent;

@property (nonatomic, strong, readonly) UIColor *color;

有了這些當前,我們就可以創立這個類的接口了:

@interface LabColor : NSObject

@property (nonatomic) double lComponent;
@property (nonatomic) double aComponent;
@property (nonatomic) double bComponent;

@property (nonatomic, readonly) double redComponent;
@property (nonatomic, readonly) double greenComponent;
@property (nonatomic, readonly) double blueComponent;

@property (nonatomic, strong, readonly) UIColor *color;

@end

維基百科提供了轉換 RGB 到 Lab 顏色空間的算法。寫成辦法之後如下所示:

- (double)greenComponent;
{
    return D65TristimulusValues[1] * inverseF(1./116. * (self.lComponent + 16) + 1./500. * self.aComponent);
}

[...]

- (UIColor *)color
{
    return [UIColor colorWithRed:self.redComponent * 0.01 green:self.greenComponent * 0.01 blue:self.blueComponent * 0.01 alpha:1.];
}

這些代碼沒什麼令人沖動的中央。風趣的是 greenComponent 屬性依賴於 lComponent 和 aComponent。不管何時設置 lComponent 的值,我們需求讓 RGB 三個 component 中與其相關的成員以及 color 屬性都要失掉告訴以堅持分歧。這一點這在 KVO 中很重要。

Foundation 框架提供的表示屬性依賴的機制如下:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key;

更詳細的如下:

+ (NSSet *)keyPathsForValuesAffecting<鍵名>;

在我們的例子中如下:

+ (NSSet *)keyPathsForValuesAffectingRedComponent
{
    return [NSSet setWithObject:@"lComponent"];
}

+ (NSSet *)keyPathsForValuesAffectingGreenComponent
{
    return [NSSet setWithObjects:@"lComponent", @"aComponent", nil];
}

+ (NSSet *)keyPathsForValuesAffectingBlueComponent
{
    return [NSSet setWithObjects:@"lComponent", @"bComponent", nil];
}

+ (NSSet *)keyPathsForValuesAffectingColor
{
    return [NSSet setWithObjects:@"redComponent", @"greenComponent", @"blueComponent", nil];
}

如今我們完好的表達了屬性之間的依賴關系。請留意,我們可以把這些屬性鏈接起來。打個比如,假如我們寫一個子類去 override redComponent 辦法,這些依賴關系依然能正常任務。

看完了下面objc的內容,讓我來再深化剖析一下
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key;

Discussion

When an observer for the key is registered with an instance of the receiving class, key-value observing itself automatically observes all of the key paths for the same instance, and sends change notifications for the key to the observer when the value for any of those key paths changes.

The default implementation of this method searches the receiving class for a method whose name matches the pattern +keyPathsForValuesAffecting, and returns the result of invoking that method if it is found. Any such method must return an NSSet. If no such method is found, an NSSet that is computed from information provided by previous invocations of the now-deprecated setKeys:triggerChangeNotificationsForDependentKey: method is returned, for backward binary compatibility.

You can override this method when the getter method of one of your properties computes a value to return using the values of other properties, including those that are located by key paths. Your override should typically call 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).

粗心就是,當一個察看者被注冊的時分,鍵值察看會察看該類一切的實例的指定鍵值對,當鍵值對改動的時分發送告訴。該辦法的默許完成形式為 + (NSSet )keyPathsForValuesAffectingValueForKey:(NSString )key;
你可以重寫這些getter辦法,前往自定義的影響屬性。

+ (NSSet *)keyPathsForValuesAffectingColor
{
    return [NSSet setWithObjects:@"redComponent", @"greenComponent", @"blueComponent", nil];
}
察看變化

我們把視圖控制器注冊為察看者來接納 KVO 的告訴,這可以用以下 NSObject 的辦法來完成:

- (void)addObserver:(NSObject *)anObserver
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
            context:(void *)context;

這會讓以下辦法:

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

在當 keyPath 的值改動的時分在察看者 anObserver 下面被調用。這個 API 看起來有一點嚇人。更蹩腳的是,我們還得記得調用以下的辦法

- (void)removeObserver:(NSObject *)anObserver
            forKeyPath:(NSString *)keyPath;
辦法解析
- (void)addObserver:(NSObject *)anObserver
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
            context:(void *)context;

參數
anObserver
要注冊KVO告訴的對象。 察看者必需完成鍵值察看辦法observeValueForKeyPath:ofObject:change:context :

keyPath
絕對於數組的關鍵途徑,要察看的屬性。 此值不能為零。

options
NSKeyValueObservingOptions值的組合,指定包括在察看告訴中的內容。

context
在ObserValueForKeyPath:ofObject:change:context:中傳遞給察看者的恣意數據。

討論
NSArray對象不可察看,因而當在NSArray對象上調用時,此辦法引發異常。 不要察看數組,而要察看數組是相關對象集合的一對多關系。

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

Parameters

keyPath
The key path, relative to object, to the value that has changed.

object
The source object of the key path keyPath.

change
A dictionary that describes the changes that have been made to the value of the property at the key path keyPath relative to object. Entries are described in Change Dictionary Keys.

context
The value that was provided when the observer was registered to receive key-value observation notifications.

參數

keyPath
絕對於對象的鍵途徑,已更改的值。

object
鍵途徑keyPath的源對象。

change
描繪對關鍵途徑keyPath絕對於對象的屬性的值所做的更改的字典。 條目在更改字典鍵中描繪。

context
注冊察看者以接納鍵值察看告訴時提供的值。

- (void)removeObserver:(NSObject *)anObserver
            forKeyPath:(NSString *)keyPath;

NSArray對象不可察看,因而當在NSArray對象上調用時,此辦法引發異常。 不要察看數組,而要察看數組是相關對象集合的一對多關系。

告訴

當我們察看的key 的 value 放生改動shi,會調用以下辦法:

- (void)willChangeValueForKey:(NSString *)key;

和:

- (void)didChangeValueForKey:(NSString *)key;
進階KVO options
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
    //假如我們需求改動前後的值,我們可以在 KVO 選項中參加 NSKeyValueObservingOptionNew 和/或 NSKeyValueObservingOptionOld。
    //更復雜的方法是用 NSKeyValueObservingOptionPrior 選項,隨後我們就可以用以下方式提取出改動前後的值:
    //id oldValue = change[NSKeyValueChangeOldKey];
    //id newValue = change[NSKeyValueChangeNewKey];
    NSKeyValueObservingOptionNew = 0x01,
    NSKeyValueObservingOptionOld = 0x02,
    NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04,//初始化(addObserver:)時,KVO就被觸發
    NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08//這能使我們在鍵值改動之前被告訴,這和-willChangeValueForKey:被觸發的時間絕對應
};

通常來說 KVO 會在 -willChangeValueForKey: 和 -didChangeValueForKey: 被調用的時分存儲相應鍵的值。

KVO 的完成

當你察看一個對象時,一個新的類會靜態被創立。這個類承繼自該對象的本來的類,偏重寫了被察看屬性的 setter 辦法。自然,重寫的 setter 辦法會擔任在調用原 setter 辦法之前和之後,告訴一切察看對象值的更改。最後把這個對象的 isa 指針 ( isa 指針通知 Runtime 零碎這個對象的類是什麼 ) 指向這個新創立的子類,對象就神奇的變成了新創立的子類的實例。
原來,這個兩頭類,承繼自本來的那個類。不只如此,Apple 還重寫了 -class 辦法,希圖詐騙我們這個類沒有變,就是本來那個類。更詳細的信息,去跑一下 Mike Ash 的那篇文章裡的代碼就能明白,這裡就不再反復。

【iOS KVO 鍵值察看】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

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