之前一直以為自己了解kvc 其實只是井底之蛙啦,真正的要把kvc原原本本的說出來還真的不是一件簡單的事情。於是今天寫下這邊文章,告誡自己要知其然還要知其所以然。key-value coding,它是一種使用字串識別符號,間接訪問物件屬性的機制,而不是直接呼叫getter 和 setter方法。通常我們使用valueforkey 來替代getter 方法,setvalue:forkey來代替setter方法。
下面是使用kvc 和 不使用 kvc的**對比
persion *persion = [ [persion alloc] init ];
//不使用kvc
persion.name = @"hufeng" ;
//使用kvc的寫法
[persion setvalue:@"hufeng" forkey:@"name"];
看出區別來了嗎?你可能會說 你寫的太簡單了,我們實際用的時候不可能有這樣複雜的類,下面我們寫個複雜點的:我們有乙個人 這個人有乙個手機類 這個手機類 有乙個電池類 我們要獲取這個電池類 比之前複雜了吧。
沒有kvc
persion
*persion = [ [persion alloc] init ];
phone
*phone = persion.phone;
battery
*battery = phone.battery;
使用kvc
battery *battery = [persion valueforkeypath: @"phone.battery" ];
注意- valueforkeypath 裡面的值是區分大小寫的,你如果寫出phone.battery 是不行的
說到這裡你可能會問 我能不能對 nsarray 呼叫kvc嗎? 答案是否定的,因為array 沒有keys啊,但是你可以對array裡面的item 使用kvc。
kvc 最常用的還是在序列化和反串行話物件。我們經常需要把json字串反序列化成我們想要的物件 下面是乙個例子 將字典用nskeyedarchiver 序列化成物件
- (id)initwithdictionary:(nsdictionary *)dictionary
return
self;
}
注意 這裡有乙個坑 當我們setvalue 給乙個沒有定義的字典值(forundefinedkey)時 會丟擲nsundefinedkeyexception異常的 記的處理此種情況
還有乙個需要注意的是kvc 並沒有型別檢驗,畢竟object-c 還是動態的啦。 還是看下面的**吧
[persion setvalue:[nsnumber numberwithinteger:1] forkey:@"name"
]; // compiles and runs
persion.name = [nsnumber numberwithinteger:1];
// won't compile: incompatible pointer types assigning to 'nsstring *' from 'nsnumber *'
setvalue forkey 得到的物件是泛型的id, 只有在使用的時候才能確定型別。你可能會問不至於吧 oc 這樣弱啊,當然不是 oc 提供了了乙個方法validatevalue來解決這個問題
@property
(nonatomic, strong) nsstring name;
- (bool)validatename:(id
*)iovalue error:(nserror**)error
person *p = [person new];
nsstring *name
= @"
jason hu"
;nserror *error
= nil;
// this call below actually calls our validatename: error: method
if ([p validatevalue:&name forkey:@"
name"
error:&error])
你可能會問寫這樣多** 才只驗證了乙個屬性 那如果我這個類有n+個屬性 難道我要寫n+個驗證方法嗎?
到這裡我們對kvc已經有了乙個初步印象,到這裡其實還只是冰山一角。
下面我們要提高更高的要求,如果讓key 支援 不區分大小寫
下面我們提到乙個方法initialize
initialize是在類或者其子類的第乙個方法被呼叫前呼叫。所以如果類沒有被引用進專案或者類檔案被引用進來,但是沒有使用,那麼initialize也不會被呼叫 ,到這裡 知道我們接下來要幹嘛了吧
+ (void)initialize );
nsmutabledictionary *translatenamedict = [nsmutabledictionary dictionary];
[self
hydratemodelproperties:[self
class
] translatedictionary:translatenamedict];
[modelproperties setobject:translatenamedict forkey:[self calculateclassname]];
}+ (void)hydratemodelproperties:(class)class
translatedictionary
:(nsmutabledictionary
*)translatedictionary
unsigned
int outcount, i;
objc_property_t *properties = class_copypropertylist(class
, &outcount);
for (i = 0; i < outcount; i++)
free(properties);
[self
hydratemodelproperties:class_getsuperclass(class
) translatedictionary:translatedictionary];
}
Vue router你真的了解了嗎
6.1 如何實現改變url的情況下頁面不進行重新整理location.hash 設定乙個值 history.pushstate 6.2 建立路由 掌握基本的結構 在使用腳手架建立的時候使用路由,能夠在src下建立乙個route檔案,裡面的index.js來配置路由資訊,並且在main.js裡面進行匯...
iOS開發之UI基礎 KVC
k vc key value coding 1.字典轉模型 dic answer dic icon dic title dic options kvc 把字典中的值,賦給當前物件制定的屬性 answer self setvalue dic answer forkeypath answer 遍歷字典中...
iOS開發 你真的會用SDWebImage?
原文 以下 在需要監聽網路狀態的方法中使用 afnetworkreachabilitymanager mgr afnetworkreachabilitymanager sharedmanager setitem customitem item 當使用者處於離線狀態時候,無法合理處理業務。於是,開始加...