簡介:
上篇我們講到了KVC,這篇我們學習KVO,全名為:Key Value Observing,直譯為:基於鍵值的觀察者。
那它有什麼用呢?KVO主要用於視圖交互方面,比如界面的某些數據變化了,界面的顯示也跟著需要變化,那就要建立數據和界面的關聯。
ObjC中提供的KVO就是解決這種問題的。以下用顯示頁面觀察學生的課程名稱變化的例子來說明KVO的使用。
學生類命名為:Student,頁面類是:PageView.
上圖來自蘋果官網,圖中的BankObject好比PageView,PersonObject好比Student,
PageView觀察Student的變化。
1、添加Student學生類。
.h
[cpp]
#import <Foundation/Foundation.h>
@interface Student : NSObject
{
NSString *name;
NSString *courseName;
}
-(void)changeCourseName:(NSString*) newCourseName;
@end
類中有name,和課程名稱courseName,添加一個可以改變課程名稱的方法changeCourseName。一會用來做對比,看直接改變課程名稱時會不會有回調。
實現文件.m
[cpp]
#import "Student.h"
@implementation Student
-(void)changeCourseName:(NSString*) newCourseName
{
courseName = newCourseName;
}
@end
實現類把方法實現了。
2、頁面類實現
.h文件
[cpp]
#import <Foundation/Foundation.h>
@class Student;
@interface PageView : NSObject
{
Student *student;
}
-(id)init:(Student*)initStudent;
@end
.m文件
[cpp]
#import "PageView.h"
#import "Student.h"
@implementation PageView
-(id)init:(Student*)initStudent
{
if (self = [super init]) {
student = initStudent;
[student addObserver:self
forKeyPath:@"courseName"
options:NSKeyValueObservingOptionOld
|NSKeyValueObservingOptionNew context:nil];
}
return self;
}
- (void) dealloc{
[student removeObserver:self forKeyPath:@"courseName" context:nil];
[super dealloc];
}
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"courseName"]) {
NSLog(@"PageView課程被改變了");
NSLog(@"PageView新課程是:%@ 老課程是:%@", [change objectForKey:@"new"],[change objectForKey:@"old"]);
}
}
@end
init初始化時,向student實例添加觀察者,在釋放的時候移除觀察者。
3、實現觀察
在main函數中
[cpp]
#import "Student.h"
#import "Course.h"
#import "PageView.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init]autorelease];
[student changeCourseName:@"數學課"];
NSLog(@"初始值:%@", [student valueForKey:@"courseName"]);
//創建頁面實例
PageView *pageview = [[[PageView alloc]init:student]autorelease];
[student setValue:@"化學課" forKey:@"courseName"];
}
return 0;
}
新建一個student的實例,設置他的課程是數學課,然後創建頁面類的時候,用student初始化。這是頁面類已經觀察著學生的課程了。
再給課程設置新的值為化學課。這時候運行打印結果:
2012-07-24 16:29:21.561 objectiveC[2192:403] 初始值:數學課
2012-07-24 16:29:21.565 objectiveC[2192:403] PageView課程被改變了
2012-07-24 16:29:21.566 objectiveC[2192:403] PageView新課程是:化學課老課程是:數學課
可以看到Pageview類中的回調被調用,Pageview接收到學生課程數據更新的信息。
4、直接改變課程信息對比
[cpp]
#import "Student.h"
#import "Course.h"
#import "PageView.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Student *student = [[[Student alloc]init]autorelease];
[student changeCourseName:@"數學課"];
NSLog(@"初始值:%@", [student valueForKey:@"courseName"]);
//創建頁面實例
PageView *pageview = [[[PageView alloc]init:student]autorelease];
[student setValue:@"化學課" forKey:@"courseName"];
[student changeCourseName:@"英語課"];
NSLog(@"直接改變的課程為:%@", [student valueForKey:@"courseName"]);
}
return 0;
}