一直沒仔細看過KVC的用法,想當然的認為可以在NSObject對象中存入任意索引值對,結果使用時碰到問題了。
一個簡單的位移動畫:
CAKeyframeAnimation *keyPosi=[CAKeyframeAnimation animationWithKeyPath:==];
我想要在動畫結束後把UILabel從螢幕上移除,於是加上動畫結束後的回調:
- ()animationDidStop:(CAAnimation *
然而看上去從回調方法的參數中似乎無法得到UILabel對象(也許提供的有api可以獲得UIlabel,希望各位看官不吝賜教),如果只是為了在這裡得到UILabel對象而去設定一個全域變數指標指向它感覺沒必要,這時候我想起了KVC,於是在建立動畫的時候加上一句:
[keyPosi setValue:label forKey:];
這樣在動畫結束的回調方法中可以通過anim參數獲得UILabel對象了:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
if (flag) {
UIView *vie=[anim valueForKey:@"xx"];
[vie removeFromSuperview];
}
}
效果已經實現,然而KVC是這樣使用的嗎?再看一個例子:
NSObject *obj = forKey:];
運行報錯:
*** Terminating app due to uncaught exception , reason:
原來setValue:forKey、setValue:forKeyPath的key(Path)參數不是隨便寫的,必須是類中定義的成員變數名(或者執行個體方法),這篇文章寫的很清楚:http://www.cnblogs.com/jay-dong/archive/2012/12/13/2815778.html。話說回來,為啥前面CAKeyframeAnimation使用的setValue:forKey的key可以成功設定?類裡肯定沒有xx這個成員變數。繼續查資料發現有個方法setValue:forUndefinedKey:,
setValue:forUndefinedKey:Invoked by setValue:forKey: when it finds no property - ()setValue:()value forUndefinedKey:(NSString *DiscussionSubclasses can method to handle the request some other way. The implementation raises an NSUndefinedKeyException.
當setValue方法的key參數在類中找不到對應成員時,會調用這個方法,重寫它可以阻止拋出NSUndefinedKeyException異常。
這樣看來,CAKeyFrameAnimation類(或者它的父類)應該是重寫了setValue:forUndefinedKey:,然而方法裡是怎樣處理從而使得valueForKey可以正確取到值呢?
objective-c的擴充機制有兩個特性:category和associative。category擴充類別,associative擴充屬性。使用associative需要匯入<objc/runtime.h>標頭檔。
利用category擴充NSObject類別,利用associative和setValue:forUndefinedKey:讓NSObject能夠存入任意索引值對。
<objc/runtime.h>- ()valueForUndefinedKey:(NSString *- ()setValue:()value forUndefinedKey:(NSString *- ()valueForUndefinedKey:(NSString *- ()setValue:()value forUndefinedKey:(NSString * ([value isKindOfClass:[NSString
現在再試下:
NSObject *obj = forKeyPath:,[obj valueForKey:]);
可以輸出了吧。