在KVC的實(shí)現(xiàn)中,依賴setter和getter的方法實(shí)現(xiàn),所以方法命名應(yīng)該符合蘋果要求的規(guī)范,否則會(huì)導(dǎo)致KVC失敗。
setValue的過程
先看一個(gè)很有趣的問題
@interface ViewController ()
@property (nonatomic, strong) NSString *Str;
@property (nonatomic, strong) NSString *str;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 情況1
self.Str = @"大寫";
self.str = @"小寫";
NSLog(@"str:%@----Str:%@",_str,_Str);
// 輸出 str:(null)----Str:小寫
// 情況2
// self.Str = @"大寫";
self.str = @"小寫";
NSLog(@"str:%@----Str:%@",_str,_Str);
// 輸出 str:(null)----Str:小寫
// 情況3
self.Str = @"大寫";
// self.str = @"小寫";
NSLog(@"str:%@----Str:%@",_str,_Str);
// 輸出 str:(null)----Str:大寫
}
輸出:(null)----123
也就是說,當(dāng)有同名大小寫屬性時(shí),遵守駝峰標(biāo)識(shí)的屬性會(huì)失效,也就是小寫開頭的屬性
為什么小寫開頭的屬性會(huì)失效呢???
我們從setter
方法找起
我們會(huì)發(fā)現(xiàn)oc
的setter
方法是遵守駝峰標(biāo)識(shí)的,比如setStr:(NSString *)Str
所以我的猜想:既然是setStr
。。。。。那么有_Str
的實(shí)例變量就優(yōu)先給他賦值,沒有就給_str
賦值
我們嘗試下
[self setValue:@"大寫" forKey:@"Str"];
[self setValue:@"小寫" forKey:@"str"];
結(jié)果還是一樣
回歸主題,我們調(diào)用[self setValue:@"大寫" forKey:@"Str"];
這個(gè)的時(shí)候,會(huì)先調(diào)用這個(gè)屬性的set方法.
那么問題也來了,如果這時(shí)候的key是沒有的屬性或者nil,那么就會(huì)導(dǎo)致調(diào)用setKey的時(shí)候,找不到方法導(dǎo)致崩潰
所以,我們可以封裝類似醬紫的安全方法
- (void)safeSetValue:(NSString *)value forKey:(NSString *)key
{
if (![key isKindOfClass:[NSString class]])
{
return;
}
@try {
[self setValue:value forKey:key];
}@catch(NSException *exception){}@finally {}
}
沒有找到setKey:
方法的時(shí)候
KVC機(jī)制會(huì)檢查
+ (BOOL)accessInstanceVariablesDirectly
方法有沒有返回YES,默認(rèn)該方法會(huì)返回YES,如果你重寫了該方法讓其返回NO的話,那么在這一步KVC會(huì)執(zhí)行setValue:forUNdefinedKey:
方法
一般我們不會(huì)閑得蛋疼去重寫+ (BOOL)accessInstanceVariablesDirectly
方法,
所以這時(shí)候既然setKey:
方法找不到了,就只能硬干了,直接去找對(duì)應(yīng)的成員變量賦值,
所以說,就算是只讀屬性(只讀屬性沒有set方法),這時(shí)候用kvc也可以賦值,因?yàn)檎也坏?code>set方法,直接對(duì)成員變量賦值
那如果找不到成員變量呢???
如果都沒有找到,那么就只能調(diào)用valueforUndefinedKey
和setValue:forUNdefinedKey:
(沒有定義這個(gè)key)拋異常
應(yīng)用
提一個(gè)問題:+ (BOOL)accessInstanceVariablesDirectly
什么時(shí)候重寫這個(gè)方法,返回NO
但我們重寫這個(gè)方法,返回NO的時(shí)候,外部對(duì)這個(gè)類進(jìn)行kvc的時(shí)候,就沒那么容易了,因?yàn)楫?dāng)找不到set方法,就直接失敗了嘛
所以你想要這個(gè)類,足夠封閉,安全的時(shí)候,可以重寫這個(gè)方法,尤其是設(shè)置SDK的時(shí)候使用
字典轉(zhuǎn)模型
服務(wù)端返回字段,有可能是id,或者其他oc的系統(tǒng)保留字段
那么就可以重寫這方法,在這塊地方去統(tǒng)一處理
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
}
valueForKey:搜索過程
有點(diǎn)多,復(fù)雜
Tips
如果valueForKeyPath:方法的調(diào)用者是數(shù)組,那么就是去訪問數(shù)組元素的屬性值
應(yīng)用:模型轉(zhuǎn)字典