Object-C — KVO & oc通知,object-ckvo

來源:互聯網
上載者:User

Object-C — KVO & oc通知,object-ckvo

索引值觀察(KVO)是基於索引值編碼的一種技術。

利用索引值觀察可以註冊成為一個對象的觀察者,在該對象的某個屬性變化時收到通知。

被觀察對象需要編寫符合KVC標準的存取方法,編寫索引值觀察分為以下三步:

(1)註冊成為觀察者。

(2)定義KVO的回調。

(3)移除觀察者。

+建立一個類Student,屬性為name,age。

@interface Student : NSObject@property(copy,nonatomic) NSString * name;@property(nonatomic) int age;@end

建立一個Parent類,作為觀察者。main函數:

    Student * student = [Student new];    Parent * parent = [Parent new];    //建立觀察者模式關係,註冊觀察者    [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];         [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];

第一個參數:(student)被觀察者。

第二個參數:(parent)觀察者。

第三個參數:(forKeyPath)鍵路徑參數,要觀察的鍵路徑,這裡觀察name和age。

第四個參數:(options)標識KVO希望變化如何傳遞給觀察者,可以使用|進行多選,這裡觀察變化的新值和舊值。

第五個參數:上下文記憶體區,通常為nil

+在parent.m的檔案中定義KVO的回調。

@implementation Parent//觀察者實現索引值觀察方法,要作為觀察者,需要實現這個方法。-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{    id oldValue = [change objectForKey:NSKeyValueChangeOldKey];    id newValue = [change objectForKey:NSKeyValueChangeNewKey];    NSLog(@"家長觀察對象:對象:%@的屬性%@的值發生了改變,舊值為:%@,新值為:%@",object,keyPath,oldValue,newValue);}

其中change是一個字典。

+如果student的name或age發生變化(最後要移除觀察者):

    Student * student = [Student new];    Parent * parent = [Parent new];    //建立觀察者模式關係,註冊觀察者    [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];    [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];    student.age = 10;    student.name = @"小明";    //結束之前需要移除觀察者    [student removeObserver:parent forKeyPath:@"age"];    [student removeObserver:parent forKeyPath:@"name"];

那麼parent上定義的的回調會自動執行,列印結果:

當然也可以多個對象觀察一個對象,建立teacher類,這樣就有兩個觀察者:

    Student * student = [Student new];    Parent * parent = [Parent new];    Teacher * teacher = [Teacher new];    //建立觀察者模式關係,註冊觀察者    [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];     [student addObserver:teacher forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];             [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld                     context:nil];     student.age = 10;     student.name = @"小明";     //結束之前需要移除觀察者     [student removeObserver:parent forKeyPath:@"age"];     [student removeObserver:parent forKeyPath:@"name"];     [student removeObserver:teacher forKeyPath:@"age"];

 

****************************************

 

另外一種情況:建立Family類,讓student成為它的一個屬性,然後讓Family成為student的觀察者,這樣註冊觀察者的方法可以寫在Family的init方法中,移除觀察者寫在Family的dealloc方法中:

Family.h檔案:

@interface Family : NSObject@property(strong,nonatomic) Student * student;-(id) initWithStudent:(Student *)student;@end

Family.m檔案:

@implementation Family-(id)initWithStudent:(Student *)student{    if(self = [super init]){        self->_student = student;        //讓當前對象成為student的觀察者        [self->_student addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld  context:nil];    }    return self;}//觀察者實現索引值觀察方法,要作為觀察者,需要實現這個方法。-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{        id oldValue = [change objectForKey:NSKeyValueChangeOldKey];    id newValue = [change objectForKey:NSKeyValueChangeNewKey];    NSLog(@"家庭觀察對象:對象:%@的屬性%@的值發生了改變,舊值為:%@,新值為:%@",object,keyPath,oldValue,newValue);}-(void)dealloc{    NSLog(@"Family dealloc...");             //移除觀察者    [self->_student removeObserver:self forKeyPath:@"name"];   //ARC所以不用寫super dealloc}@end

main:

    Student * student = [Student new];    Family * family = [[Family alloc]initWithStudent:student];    student.name = @"hehe";

可以看到KVO的方式耦合度較高,類之間有直接的關係。接下來看通知。

自訂通知

通知是iOS開發架構中的一種設計模式,通知一般用於M、V、C之間的資訊傳遞。比如設定頁面、設定App皮膚。

NSNotification

使用通知之前,我們要建立通知對象。 Notification對象有兩個重要的成員變數: name 和 object。一般name用來唯一標示一個通知對象,object指通知寄件者。

Notification對象包含一個參數,就是字典(選擇性參數),這個字典中儲存一些傳值過程中的資訊,供接收者使用。系統要求這個參數是不可變字典。

NSNotificationCenter

通知建立好後就可以在必要的時候發送通知,發送通知的時候,需要一個控制中心來發送通知,這個控制中心就是通知中樞。

通知中樞是通知機制架構的大腦。它允許我們註冊通知監聽者、發送通知、移除通知監聽者。

一般系統通知不需要我們發送通知。只需要我們註冊通知監聽者、 移除通知監聽者。比如監聽視頻是否播放完成。

栗子,Teacher發送通知。學生接收:

頁面結構:

老師有一個發送方法。Teacher.h檔案:

@interface Teacher : NSObject- (void) sendMessage;@end

Teacher.m檔案:

#import "MacroDefinition.h"@implementation Teacher- (void)sendMessage{    NSNotification * myNotification = [NSNotification notificationWithName:kMyNotificationName object:self userInfo:@{@"content":@"同學們,星期一放假,不用來了"}];    //發送通知    //需要使用通知中樞來發送。    //通知中樞是一個單例模式的    NSNotificationCenter * center = [NSNotificationCenter defaultCenter];    [center postNotification:myNotification];}@end

其中NSNotification中的notificationWithName因為別的地方也會用到,所以寫成了宏定義放到了單獨的.h檔案MacroDefinition中,檔案中寫了:#define kMyNotificationName @"customNotification" 。userinfo是一個字典,可以存通知的內容。

先寫上Student的接收通知後的回調方法:

Student.h檔案:

@interface Student : NSObject//可以跟一個參數,但是只能是NSNotification對象。-(void)receiveMessage:(NSNotification *) notification;@end

Student.m檔案:

@implementation Student- (void)receiveMessage:(NSNotification *)notification{    NSLog(@"對象%@發出來名稱為:%@的通知,附加資料為:%@",notification.object,notification.name,[notification.userInfo objectForKey:@"content"]);}

main引入:

#import "MacroDefinition.h"
#import "Teacher.h"
#import "Student.h"

        Teacher * teacher = [Teacher new];        Student * student1 = [Student new];        Student * student2 = [Student new];        Student * student3 = [Student new];        //訂閱通知中樞        NSNotificationCenter * center = [NSNotificationCenter defaultCenter];        //註冊,第一個參數是觀察者,第二個參數是觀察者拿到自己關心的通知之後,所要調用的方法,第三個參數為觀察者關心的通知的名稱,第四個參數為觀察者關心的發出對象。        [center addObserver:student1 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];        [center addObserver:student2 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];        [center addObserver:student3 selector:@selector(receiveMessage:) name:kMyNotificationName object:nil];        //發送        [teacher sendMessage];        //道理上來說應該移除訂閱者        [center removeObserver:student1 name:kMyNotificationName object:nil];        [center removeObserver:student2 name:kMyNotificationName object:nil];        [center removeObserver:student3 name:kMyNotificationName object:nil];    

列印結果:

通知中樞是一個單例模式的,所以kMyNotificationName,main和Teacher.m中的是同一個,所以這兩個檔案用的宏定義是一樣的。

這樣這兩個類並沒有直接的關係只是通過通知中樞來傳遞訊息。關於通知的更多內容後邊再補充吧=。=

 

KVO和通知的區別:

1:KVO的類是由直接聯絡的,耦合度較高。而通知是沒有直接聯絡的。

2:KVO是只要屬性發生改變,觀察者就會被響應。通知是被觀察者先主動發出通知,然後觀察者註冊監聽後再來進行響應,比KVO多了發送通知的一步,但是其優點是監聽不局限於屬性的變化,還可以對多種多樣的狀態變化進行監聽,監聽範圍廣,使用也更靈活。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.