iOS中KVC與KVO的應用解析
一、NSKeyValueCoding(KVC)
1、從一個小例子引入
KVC鍵值編碼是Object-C為我們提供的一種對成員變量指派的方法。在探讨其方法之前,我們先來看一個小例子:
首先,建立一個資料模型model類:
//.h檔案
#import <Foundation/Foundation.h>
@interface Model : NSObject
{
@public//将成員變量設定為公有的 以便其他檔案有通路權限
NSString * str;
}
@end
我們在其他檔案中有兩種方法str進行指派和取值:
Model * model = [[Model alloc]init];
model->str=@"312";//普通方法指派
[model setValue:@"321" forKey:@"str"];//kvc指派
NSLog(@"%@",model->str);//普通方法取值
NSLog(@"%@",[model valueForKey:@"str"]);//kvc取值
同樣的,對于用@property聲明的變量,使用kvc的效果和使用點文法,setter,getter方法的效果是一樣的。
2、KVC有關函數方法詳解
通過上面的例子,我們已經可以簡單了解KVC是幹什麼的了,下面是一些常用方法。
+ (BOOL)accessInstanceVariablesDirectly;
這個方法類似一個開關,預設傳回為YES,表示支援KVC方式指派,也可以在子類中将其重寫,如果傳回為NO,則再進行KVC會抛出異常。
- (id)valueForKey:(NSString *)key;
通過鍵取值
- (void)setValue:(id)value forKey:(NSString *)key;
通過字元串鍵給成員變量指派
- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
系統預設實作的方法,驗證一個鍵值是否有效
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
将取到的值放入一個可變數組中
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
将取到的值放入可變的有序集合中
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
将取到的值放入可變的集合中
- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
上面這兩個方法分别是通過路徑指派與取值,資料結構類似地圖,比如在model類中有一個成員變量model2,在Model2類中有一個字元串,我們可以通過如下的方式指派取值
//Model.h
#import "Model2.h"
@public
Model2 * model2;
//Model2.h
@interface Model2 : NSObject
@public
NSString * str2;
//其他檔案
Model2 * model2 = [[Model2 alloc]init];
model->model2=model2;
[model setValue:@"123" forKeyPath:@"model2.str2"];
NSLog(@"%@",[model valueForKeyPath:@"model2.str2"]);
- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
上面三個方法與前面類似,隻是是從路徑取值的。
- (id)valueForUndefinedKey:(NSString *)key;
這個方法可以擷取沒有提前定義的成員變量的值,比如運作時建立的,下面這個方法是給未定義的成員變量指派
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
注意:這兩個方法預設的實作會抛出異常,子類必須重寫才能使用。
- (void)setNilValueForKey:(NSString *)key;
将成員變量置為nil
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
根據鍵值擷取鍵值對字典
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
通過字典對成員變量同意指派,經常使用
二、NSKeyValueObservingCustomization(KVO)
KVO是一種消息監聽機制,可以在某個量發生變化的時候将消息傳送給監聽者,是以廣泛用于傳值,界面低耦合等邏輯中。KVO機制的核心是以下三個方法:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
使用這個方法注冊一個監聽者,參數解釋如下:
observer:監聽者對象
keyPath:監聽的參數
options:監聽選項
context:參數傳遞
監聽的選項枚舉如下:
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
NSKeyValueObservingOptionNew = 0x01,//回調的字典中存放新值
NSKeyValueObservingOptionOld = 0x02,//回調的字典中存放舊值
NSKeyValueObservingOptionInitial ,//值改變前進行回調
NSKeyValueObservingOptionPrior//改變前後都進行回調
};
//回調字典後面會解釋
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context ;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
這兩個方法都是用來移除監聽者
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
這個方法是監聽對象資料改變時回調的方法,change是一個字典,字典中根據監聽的選項不同,存放不同的值(新或者舊)。context是傳遞的參數。
代碼示例:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
model = [[Model alloc]init];
//添加監聽者
[model addObserver:self forKeyPath:@"str" options:NSKeyValueObservingOptionNew context:@"321"];
[model setValue:@"qw" forKey:@"str"];
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"str"]) {
NSLog(@"%@",context);
}