KVC的使用
通常情況下,我們都是通過屬性或者定義存取方法來對(duì)實(shí)例變量進(jìn)行存取,但是除此之外芹橡,我們也可以通過Key-Value-Coding(KVC)鍵值編碼來存取的實(shí)例變量的值前弯。
使用KVC過程:
首先,我們定義一個(gè)Person類修肠,代碼如下:
/*
*Person.h
*/
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
NSString *_name;
}
@end
/*
*Person.m
*/
#import "Person.h"
@implementation Person
@end
然后創(chuàng)建Person類的實(shí)例贺辰,并使用KVC對(duì)_name實(shí)例變量進(jìn)行賦值和取值操作:
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
//將person的實(shí)例變量_name賦值為SmithJackyson
[person setValue:@"SmithJackyson" forKey:@"_name"];
//取出person的實(shí)例變量_name的值
NSString *name = [person valueForKey:@"_name"];
NSLog(@"name = %@",name);
}
return 0;
}
下面為打印結(jié)果:
2016-01-14 20:42:14.098 test[1559:113739] name = SmithJackyson
Program ended with exit code: 0
如果A類的屬性是一個(gè)B類,那么為B類的屬性存取值就需要鍵路徑訪問屬性
假設(shè)Student類有一個(gè)Course類的屬性_course,其中Course類有一個(gè)屬性表示課程名稱NSString *_courseName;
下面通過鍵路徑訪問屬性:
#import <Foundation/Foundation.h>
#import "Student.h"
#import "Course.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//注意:使用KVC是為實(shí)例存取實(shí)例變量饲化,所以要初始化莽鸭,并且為student的_course實(shí)例變量賦值為course,否則無法正確賦值
Student *student = [[Student alloc] init];
Course *course = [[Course alloc] init];
[student setValue:course forKey:@"_course"];
//為student實(shí)例變量_course的屬性_courseName賦值
[student setValue:@"English" forKeyPath:@"_course._courseName"];
//取得student實(shí)例變量_course的屬性_courseName的值
NSString *courseName = [student valueForKeyPath:@"_course._courseName"];
NSLog(@"courseName = %@",courseName);
}
return 0;
}
下面是打印結(jié)果:
2016-01-14 21:15:59.094 test[1867:123245] courseName = English
Program ended with exit code: 0
如果屬性是基本數(shù)據(jù)類型吃靠,可以使用字符串值直接賦值給屬性硫眨,取值時(shí)用字符串變量接受
KVO的使用
KVO,即:key-value observing巢块,提供一種機(jī)制礁阁,假設(shè)A對(duì)象觀察B對(duì)象的指定屬性C,當(dāng)B對(duì)象的屬性C的值發(fā)生變化族奢,KVO會(huì)通知相應(yīng)的觀察者A乓序,A對(duì)象可以進(jìn)行某些操作,比如更新視圖
使用過程:
- 注冊(cè)霜威,指定觀察哪些對(duì)象的哪些屬性
- 實(shí)現(xiàn)回調(diào)方法
- 移除觀察
首先定義一個(gè)Person類眨猎,代碼如下:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic,copy)NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
#import "Person.h"
@implementation Person
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
_name = name;
}
return self;
}
@end
然后在ViewController中使用KVO,代碼如下:
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
{
Person *person;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
person = [[Person alloc] initWithName:@"John"];
//為person對(duì)象的屬性name添加觀察者為ViewController
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
//可以通過下面兩種方式改變name的值弥姻,都會(huì)觸發(fā)回調(diào)方法
person.name = @"SmithJackyson";
[person setValue:@"SmithJackyson" forKey:@"name"];
}
//實(shí)現(xiàn)KVO回調(diào)方法南片,只要person的屬性name發(fā)生變化,就會(huì)回調(diào)這個(gè)方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
//change字典里存的內(nèi)容是根據(jù)你注冊(cè)時(shí)的選項(xiàng)option決定的庭敦,如果為NSKeyValueObservingOptionNew疼进,則字典里存的是改變后的值,key為new秧廉,同樣NSKeyValueObservingOptionOld伞广,則字典里存的是改變前的值,key為old疼电,如果兩者都有嚼锄,則字典存儲(chǔ)著兩個(gè)值
if ([keyPath isEqualToString:@"name"] && object == person) {
NSLog(@"now name = %@",person.name);
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
運(yùn)行結(jié)果如下:
2016-01-15 16:17:29.102 test[1752:94898] now name = SmithJackyson
2016-01-15 16:17:29.102 test[1752:94898] now name = SmithJackyson
最后還需要移除觀察者
- (void)dealloc
{
[person removeObserver:self forKeyPath:@"name"];
}
當(dāng)需要手動(dòng)通知時(shí),可以重寫Person類的下面的方法告訴cocoa哪些鍵值要使用自動(dòng)通知:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{
if([key isEqualToString:@"name"]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
返回YES表示自動(dòng)通知蔽豺,當(dāng)返回NO時(shí)区丑,表示手動(dòng)通知,在值發(fā)生變化時(shí)需要調(diào)用willChangeValueForKey:和didChangeValueForKey:方法通知調(diào)用者修陡。