KVC 與 KVO 是 Objective-C 的關(guān)鍵概念.
KVC:
KVC,即是指 NSKeyValueCoding, 一個(gè)非正式的 Protocol, 提供一種機(jī)制來間接訪問對(duì)象的屬性. KVO就是基于KVC實(shí)現(xiàn)的關(guān)鍵技術(shù)之一.
一個(gè)對(duì)象擁有某些屬性.比如說,一個(gè)Person對(duì)象有一個(gè)name 和一個(gè)address屬性.以KVC說法,Person 對(duì)象分別有一個(gè)value對(duì)應(yīng)他的 name和address的key. key只是一個(gè)字符串,它對(duì)應(yīng)的值可以是任意類型的對(duì)象. 從最基礎(chǔ)的層次上看,KVC有一兩個(gè)方法: 一個(gè)是設(shè)置key的值,另一個(gè)是獲取key的值.如下面的例子:
void changeName(Person *p, NSString *newName){
//using the KVC accessor (getter) method
NSString *originalName = [p valueForKey:@"name"];
//using the KVC accessor (setter) method
[p setValue: newName forKey: @"name"];
NSLog(Changed %@'s name to: %@", originalName, newName);
}
現(xiàn)在,如果Person 有另一個(gè)key 配偶(spouse),spouse的key值是另一個(gè)Person對(duì)象,用KVC可以這樣寫:
void logMarriage(Person *p){
// just using the accessor again, same as example above
NSString *personsName =[p valueForKey:@"name"];
// this line is different, because it is using
// a "key path" instead of a normal "key"
NSString *spousesName = [p valueForKeyPath:@"spouse.name"];
NSLog(@"%@ is happily married to %@", personsName, spousesName);
}
key與 key pat 要區(qū)分開來,key可以從一個(gè)對(duì)象中獲取值,而key path 可以將多個(gè)key用點(diǎn)號(hào)"." 分隔連接起來,比如:
[p valueForKeyPath:@"spouse.name"];
相當(dāng)于這樣.....
[[p valueForKey:@"spouse"] valueForKey: @"name"];
# iOS 中KVC的總結(jié) ##
一、 KVC介紹
kvc就是鍵值編碼(key-value),說白了就是通過指定的key獲得想要的值value。而不是通過調(diào)用Setter、Getter方法訪問。*
二、 KVC的強(qiáng)大之處
1 .訪問私有變量
一個(gè)類中的私有變量,不能直接通過Setter、Getter方法訪問。但是卻可以通過KVC來訪問。舉例:
一個(gè)類如下:
@interfaceDog : NSObject{@private
double height;
}
這里的私有變量 height ,假如直接使用Setter、Getter方法訪問,就會(huì)出現(xiàn)下面的錯(cuò)誤。
這時(shí)候可以使用KVC來訪問這個(gè)私有變量:
Dog *dog = [[Dog alloc]init];[dogsetValue:@12forKey:@"height"];//給私有變量賦值NSLog(@"dog's height is = %@",[dogvalueForKey:@"height"]);//讀取私有變量的值
實(shí)際使用舉例
利用kvc的這個(gè)特性,我們可以訪問系統(tǒng)里的一些私有變量。
例如:在UIPageControl里面有兩個(gè)私有變量:
UIImage*? ? ? ? _currentPageImage;UIImage*? ? ? ? _pageImage;
我們可以通過kvc來進(jìn)行讀取和賦值:
UIPageControl *pageControl = [[UIPageControl alloc]init];//設(shè)置值[pageControlsetValue:[UIImageimageNamed:@"XX"]forKeyPath:@"_currentPageImage"];[pageControlsetValue:[UIImageimageNamed:@"XX"]forKeyPath:@"_pageImage"];//讀取值UIImage *currentImage = [pageControlvalueForKey:@"_currentPageImage"];UIImage *pageImage = [pageControlvalueForKey:@"_pageImage"];
這樣我們就可以設(shè)置當(dāng)前顯示和未顯示到腳標(biāo)的樣式了。
2. 使用KVC直接訪問 NSArray 或者 NSSet 的屬性值
NSArray/NSSet等都支持KVC,這里舉一個(gè)例子:
NSArray *books= @[book1, book2, book3];NSArray *names = [booksvalueForKeyPath:@"name"];NSLog(@"%@", [booksvalueForKeyPath:@"@avg.price"]);//使用kvc直接打印出來書的平均價(jià)格
其中,book是一個(gè)書類,有一個(gè)屬性是name,一個(gè)屬性是price。
3. 使用KVC將字典(json)轉(zhuǎn)化成模型
// 定義一個(gè)字典NSDictionary *dict = @{@"name"? :@"jack",@"money" :@"20.7",? ? ? ? ? ? ? ? ? ? ? ? };// 創(chuàng)建模型? ? Person *p = [[Person alloc] init];// 字典轉(zhuǎn)模型? ? [p setValuesForKeysWithDictionary:dict];NSLog(@"person's name is the %@",p.name);
}
注意:
(1). key的值必須正確,如果拼寫錯(cuò)誤,會(huì)出現(xiàn)異常
(2). 當(dāng)key的值是沒有定義的,valueForUndefinedKey:這個(gè)方法會(huì)被調(diào)用,如果你自己寫了這個(gè)方法,key的值出錯(cuò)就會(huì)調(diào)用到這里來
(3). 因?yàn)轭恔ey反復(fù)嵌套,所以有個(gè)keyPath的概念,keyPath就是用.號(hào)來把一個(gè)一個(gè)key鏈接起來,這樣就可以根據(jù)這個(gè)路徑訪問下去
(4). NSArray/NSSet等都支持KVC
KVO:
Key-Value Observing (KVO)
Key-Value Observing(KVO)建立在KVC之上 ,它能夠觀察一個(gè)對(duì)象的KVC key path 值的變化.舉個(gè)例子,用代碼觀察一個(gè)person對(duì)象的address變化,以下是實(shí)現(xiàn)的三個(gè)方法:
.watchPersonForChangeOfAddress:實(shí)現(xiàn)觀察
.observeValueForKeyPath:ofObject:change:context: 在被觀察的key path的值變化時(shí)調(diào)用.
.dealloc 停止觀察
static NSString *const KVO_CONTEXT_ADDRESS_CHANGED = @"KVO_CONTEXT_ADDRESS_CHANGED"
@implementation PersonWatcher
-(void)watchPersonForChangeOfAddress:(Person *)p
{? ??
// this begins the observing
[p addObserver:self
forKeyPath:@"address"
options:0
context:KVO_CONTEXT_ADDRESS_CHANGED];
// keep a record of all the people being observed,
// because we need to stop observing them in dealloc
[m_observedPeople addObject:p];
}
// whenever an observed key path changes, this method will be called
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void*)context
{
// use the context to make sure this is a change in the address,
// because we may also be observing other things
if(context == KVO_CONTEXT_ADDRESS_CHANGED) {
NSString *name = [object valueForKey:@"name"];
NSString *address = [object valueForKey:@"address"];
NSLog(@"%@ has a new address: %@", name, address);
}
}
-(void) dealloc;
{
// must stop observing everything before this object is
// deallocated, otherwise it will cause crashes
for(Person *p in m_observedPeople){
[p removeObserver:self forKeyPath:@"address"];
}
[m_observedPeople release];
m_observedPeople = nil;
[super dealloc];
}
-(id) init;
{
if(self = [super init]){
m_observedPeople = [NSMutableArraynew];
}
returnself;
}
@end
這就是 KVO 的作用,它通過 key path 觀察對(duì)象的值,當(dāng)值發(fā)生變化的時(shí)候會(huì)收到通知。
一、KVO介紹
KVO就是觀察者模式,說白了就是你關(guān)心的一個(gè)值改變了,你就會(huì)得到通知。你就可以在你想處理的地方處理這個(gè)值。
二、KVO的使用
一般分為三步:
注冊監(jiān)聽
使用方法:
/***? 添加KVO監(jiān)聽者**@param observer 觀察者(監(jiān)聽器)*@param keyPath? 屬性名(要觀察的屬性)*@param options*@param context? 傳遞的參數(shù)*/- (void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context;
例子:
//為對(duì)象p添加一個(gè)觀察者(監(jiān)聽器)
[p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:@"test"];
2.設(shè)置監(jiān)聽事件
/***
當(dāng)利用KVO監(jiān)聽到某個(gè)對(duì)象的屬性值發(fā)生了改變,就會(huì)自動(dòng)調(diào)用這個(gè)
**@param keyPath
哪個(gè)屬性被改了*@param object? 哪個(gè)對(duì)象的屬性被改了*@param change? 改成咋樣*@param context 當(dāng)初addObserver時(shí)的context參數(shù)值*/
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context{??
NSLog(@"%@ %@ %@ %@", object, keyPath, change, context);
}
3.取消監(jiān)聽
//釋放KVO監(jiān)聽-(void)dealloc{? ? [premoveObserver:selfforKeyPath:@"test"];
}
這些都是網(wǎng)上摘抄自己跟著敲了一遍溫習(xí)了一下,練習(xí)代碼KVC???? KVO??