你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS SDK詳解之KVO

IOS SDK詳解之KVO

編輯:IOS開發綜合

 

 前言:KVC和KVO是幫助我們駕馭objective C動態特性工具。KVO是建立在KVC基礎上的,所以不了解KVC的同學可以參見我的這篇博客。這裡我不會再重復講解KVC。
 
本文的內容

KVO的定義
KVO的典型使用場景。
手動KVO
幾點KVO要說的地方


一 KVO的定義

KVO提供了一種key-value-observing的機制,也就是說可以通過監聽key,來獲得value的變化。用來在對象之間監聽狀態變化。使用KVO的類要遵循 協議,事實上,任何繼承自NSObject的類,都遵循了這個協議。而Object C中,幾乎所有的類都源自NSObject

使用KVO通常分為三步

1.1 訂閱想要監聽的keypath

用函數

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

注冊通知

observer:觀察者,也就是KVO通知的訂閱者。訂閱著必須實現
observeValueForKeyPath:ofObject:change:context:方法 keyPath:描述將要觀察的屬性,相對於被觀察者。 options:KVO的一些屬性配置;有四個選項。 context: 上下文,這個會傳遞到訂閱著的函數中,用來區分消息,所以應當是不同的。

options所包括的內容

NSKeyValueObservingOptionNew:change字典包括改變後的值 NSKeyValueObservingOptionOld:change字典包括改變前的值 NSKeyValueObservingOptionInitial:注冊後立刻觸發KVO通知 NSKeyValueObservingOptionPrior:值改變前是否也要通知(這個key決定了是否在改變前改變後通知兩次)

1.2 響應狀態變化

每當監聽的keyPath發生變化了,就會在這個函數中回調。

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
keyPath:被監聽的keyPath , 用來區分不同的KVO監聽。 object: 被觀察修改後的對象(可以通過object獲得修改後的值) change:保存信息改變的字典(可能有舊的值,新的值等) context:上下文,用來區分不同的KVO監聽。

1.3 在適當的時候,取消訂閱

通常使用兩個函數

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

一般在remove的時候會這麼寫,因為remove的時候,無法判讀啊remove是否成功了

    @try {
        [object removeObserver:self forKeyPath:keyPath];
    }
    @catch (NSException *exception) {
        NSLog(@%@,exception);
    }

二 KVO的典型使用場景 - model 與 view的同步

這裡,你將看到一個完整的KVO的例子。和上篇KVC一樣,我寫了個類似的demo。點擊random會隨機改變User的age,然後UI上要進行同步顯示出新的和舊的age。
這裡寫圖片描述

實現過程如下:
定義了一個User類來作為Model

@interface User : NSObject
@property (strong,nonatomic) NSString * name;
@property (nonatomic) NSUInteger age;
@end

定義兩個靜態的變量,一個作為keyPath,一個作為context

static  NSString * observename = @age;
static void * privateContext = 0;

然後在viewWillAppear中注冊(訂閱)KVO,在viewWillDisappear中刪除KVO

-(void)viewWillAppear:(BOOL)animated{
    [self.user addObserver:self
                forKeyPath:observename
                   options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:privateContext];
}
-(void)viewWillDisappear:(BOOL)animated{
    @try {
        [self.user removeObserver:self forKeyPath:observename];
    }
    @catch (NSException *exception) {
        NSLog(@%@,exception);
    }
}

當點擊random的時候,age會改變

- (IBAction)random:(id)sender {
    self.user.age = arc4random()%100 +1;
}

然後,在上面提到的函數中進行model和view的同步

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if (context == privateContext) {
        if ([keyPath isEqualToString:observename]) {
            NSNumber * old = [change objectForKey:NSKeyValueChangeOldKey];
            NSNumber * new = [change objectForKey:NSKeyValueChangeNewKey];
            self.lastvalue.text = [NSString stringWithFormat:@%@,old];
            self.newvalue.text = [NSString stringWithFormat:@%@,new];
        }
    }
}

三 手動KVO

KVO的實現,是對注冊的keyPath中自動實現了兩個函數,在Setter中,自動調用。

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

可能有時候,我們要實現手動的KVO
這時候需要關閉自動生成KVO通知,然後手動的調用,手動通知的好處就是,可以靈活加上自己想要的判斷條件。例如

+(BOOL)automaticallyNotifiesObserversOfAge{
    return NO;
}
-(void)setAge:(NSUInteger)age{
    if (age < 22) {
        return;
    }
    [self willChangeValueForKey:@age];
    _age = age;
    [self didChangeValueForKey:@age];
}

四 KVO要提到的幾點

KVO和Context

由於Context通常用來區分不同的KVO,所以context的唯一性很重要。通常,我的使用方式是通過在當前.m文件裡用靜態變量定義。

static void * privateContext = 0;

KVO與線程

KVO的響應和KVO觀察的值變化是在一個線程上的,所以,大多數時候,不要把KVO與多線程混合起來。除非能夠保證所有的觀察者都能線程安全的處理KVO

監聽變化的值

改變前和改變後分別為

id oldValue = change[NSKeyValueChangeOldKey];
id newValue = change[NSKeyValueChangeNewKey];

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