一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

有趣的KVC-幾行代碼打造一個(gè)萬能容器對(duì)象

 xiaotianyueye 2016-12-07


來源:http://


引言


kvc是每個(gè)iOS開發(fā)者在學(xué)習(xí)obj-C時(shí)都學(xué)過的特性,但是由于obj-C學(xué)起來并不難,所以很多初學(xué)者把大部分時(shí)間都放在熟悉cocoa框架以及對(duì)iOS開發(fā)相關(guān)的API掌握上。其實(shí)在項(xiàng)目中巧用kvc可以大大提高開發(fā)效率減少代碼量,下面我們進(jìn)入正題。


定義


KVC(Key-Value-Coding)意思是鍵值編碼。在iOS中,提供了一種方法通過使用屬性的名稱(也就是Key)來間接訪問對(duì)象的屬性方法。


說的有點(diǎn)兒拗口,實(shí)際上就是通過類定義我們可以看到類的各種屬性,那么使用屬性的名稱我們就能訪問到類實(shí)例化后的對(duì)象的這個(gè)屬性值。


KVC特性


1.無setter/getter方法也可以直接去找對(duì)應(yīng)名稱的變量操作


KVC中最常見的也是最基本的調(diào)用方法:


//調(diào)用這個(gè)方法找到與key匹配的變量并把value賦值給它
- (void)setValue:(nullable id)value forKey:(NSString *)key;
//調(diào)用這個(gè)方法找到與key匹配的變量并返回
- (nullable id)valueForKey:(NSString *)key;


那么上面的方法對(duì)比直接調(diào)用getter/setter方法時(shí)有什么區(qū)別呢?


  • 調(diào)用上面的方法其實(shí)默認(rèn)會(huì)調(diào)用接收消息對(duì)象的getter/setter方法來對(duì)與key鍵匹配的屬性進(jìn)行讀/寫操作

  • 如果接受消息的對(duì)象并沒有實(shí)現(xiàn)相應(yīng)的getter/setter方法的話,會(huì)直接訪問對(duì)象中的匹配變量作相應(yīng)操作(包括私有變量)


第一點(diǎn)印證實(shí)例:


@interface LXObj : NSObject
{    
NSString *ivar;}
@end


在.m文件中的代碼空空如也:


@implementation LXObj
@end


然后執(zhí)行以下代碼:


LXObj *obj = [[LXObj alloc] init];obj.ivar = @'i am a ivar';


發(fā)現(xiàn)靜態(tài)解析器編譯不過去……

如果按照以下代碼去操作ivar變量即可使程序正常運(yùn)行:


LXObj *obj = [[LXObj alloc] init];
[obj setValue:@'i am a ivar' forKey:@'ivar'];NSLog(@'%@', [obj valueForKey:@'ivar']);


運(yùn)行結(jié)果如下:




那么我們?cè)賮砜匆幌翶VC訪問下的所謂obj-C私有變量,首先在類中添加私有變量:


@interface LXObj : NSObject {
@private NSString *privateIvar;}


或者在類擴(kuò)展中聲明變量:


@interface LXObj ()
@property (nonatomic, copy) NSString *privateIvar;
@end


為了解釋的更明白,讓所有人(包括一些初學(xué)obj-C的小伙伴)看懂,先用普通的方式訪問:




都編譯不過去,靜態(tài)分析器就幫我們找到了錯(cuò)誤,那么我們換KVC方式訪問:


LXObj *obj = [[LXObj alloc] init];[obj setValue:@'i am a private ivar' forKey:@'privateIvar'];NSLog(@'%@', [obj valueForKey:@'privateIvar']);


然后運(yùn)行,發(fā)現(xiàn)可以正常運(yùn)行:



看到這,你會(huì)得出或者印證你以前學(xué)習(xí)obj-C時(shí)書上提到的:obj-C實(shí)際上并不存在真正的私有變量,因?yàn)橹灰雷兞棵Q就可以訪問且操作這個(gè)變量。


你不要萌萌的瞪著眼睛問我:我們?yōu)樯哆€要遵守規(guī)則把變量寫在.m內(nèi)的類擴(kuò)展中呢?


因?yàn)楫?dāng)你的app提交到appstore中被人下載得到下載包后,別人反編譯分分鐘就能看到你的項(xiàng)目頭文件,類名和方法。


2.使用KVC會(huì)自動(dòng)開/封箱


如果你想設(shè)置一個(gè)標(biāo)準(zhǔn)量,在調(diào)用- (void)setValue:(nullable id)value forKey:(NSString *)key方法之前需要將它們封箱:


先給LXObj類添加一個(gè)floatNum屬性:


@property (nonatomic, assign) float floatNum;


然后執(zhí)行下面代碼:


LXObj *obj = [[LXObj alloc] init];[obj setValue:[NSNumber numberWithFloat:0.1] forKey:@'floatNum'];


這時(shí),- (void)setValue:(nullable id)value forKey:(NSString *)key方法會(huì)先開箱取出該值,再調(diào)用- (void)setFloatNum:方法或者直接更改floatNum實(shí)例變量,反之:


LXObj *obj = [[LXObj alloc] init];NSLog(@'%@', [obj valueForKey:@'floatNum']);


代碼中[obj valueForKey:@'floatNum']方法會(huì)先取出floatNum屬性的值并封箱打印出來。


3.鍵路徑


當(dāng)類中包含其他類類型的屬性時(shí),可以直接使用鍵路徑來操作這個(gè)屬性內(nèi)部的變量。


先定義一個(gè)LXSubObj類,其中包含一個(gè)屬性subIvar:


@interface LXSubObj : NSObject@property (nonatomic, copy) NSString *subIvar;@end


然后往LXObj中添加一個(gè)LXSubObj類型的屬性:


@class LXSubObj;@interface LXObj : NSObject@property (nonatomic, strong) LXSubObj *subObj;@end


此時(shí)要操作LXObj對(duì)象中的subObj屬性的subIvar可以使用


LXObj *obj = [[LXObj alloc] init];obj.subObj = [[LXSubObj alloc] init];[obj setValue:@'operate subObj's subIvar' forKeyPath:@'subObj.subIvar'];NSLog(@'%@', [obj valueForKeyPath:@'subObj.subIvar']);


運(yùn)行結(jié)果:




Ps:需要注意,如果LXObj下有一組類型為LXSubObj的數(shù)組作為屬性,那么NSArray實(shí)現(xiàn)valueForKeyPath:的方法是循環(huán)遍歷它的內(nèi)容并向每個(gè)對(duì)象發(fā)送信息。也就是說NSArray會(huì)向每個(gè)在自身之中的LXSubObj對(duì)象發(fā)送參數(shù)以subIvar作為鍵路徑的valueForKeyPath:消息。


4.批處理


這個(gè)由于各位在初學(xué)iOS階段可能就用到過,而且平時(shí)開發(fā)也會(huì)使用到,就一筆帶過吧:


// 根據(jù)所給字典一一對(duì)應(yīng)的設(shè)置接收消息對(duì)象內(nèi)的屬性值
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
// 根據(jù)數(shù)組keys一一對(duì)應(yīng)的從接收消息對(duì)象內(nèi)取出對(duì)應(yīng)的值生成字典返回
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;


5.快速運(yùn)算


通過快速運(yùn)算特性可以節(jié)約開發(fā)成本,簡化代碼,先把上面LXObj內(nèi)部的subObj改為NSArray類型(這里用到了泛型語法):


@class LXSubObj;
@interface LXObj : NSObject
@property (nonatomic, strong) NSArray *subObjs;
@end


.m中初始化數(shù)組subObjs:


@implementation LXObj
- (NSArray *)subObjs{    
if (!_subObjs) {        LXSubObj *subObj1 = [[LXSubObj alloc] init];        LXSubObj *subObj2 = [[LXSubObj alloc] init];        _subObjs = @[subObj1, subObj2];    }  
 return _subObjs;}
@end


然后執(zhí)行下面的代碼:


LXObj *obj = [[LXObj alloc] init];
NSLog(@'%@', [obj valueForKeyPath:@'subObjs.@count']);


運(yùn)行結(jié)果:



類似@count的例子還有很多:

  • @avg         //獲取平均數(shù)

  • @min        //獲取最小數(shù)

  • @max       //獲取最大數(shù)

  • @distinctUnionOfObjects    //過濾重復(fù)值


用kvc實(shí)現(xiàn)一個(gè)萬能容器對(duì)象的方法


終于到的正題,這里我們?yōu)榱诵蜗笠恍密囎觼砼e例。下面的LXCar類沒有任何屬性但是理論上可以存任意數(shù)量的任意類型的屬性。


LXCar.h文件內(nèi)代碼:


@interface LXCar : NSObject
// 父老鄉(xiāng)親們,看清楚,這容器就是空的?。?!
@end


LXCar.m內(nèi)代碼:


@interface LXCar ()// 用來放置屬性鍵值對(duì)的字典@property (nonatomic, strong) NSMutableDictionary *mPropertiesDict;@end@implementation LXCar// 沒有對(duì)應(yīng)key的setter方法且沒有找到對(duì)應(yīng)key的屬性時(shí)調(diào)用- (void)setValue:(id)value forUndefinedKey:(NSString *)key{    if (!key || [key isEqualToString:@''])        return;    if (!_mPropertiesDict) {        _mPropertiesDict = [NSMutableDictionary dictionary];    }    [_mPropertiesDict setValue:value forKey:key];}// 沒有對(duì)應(yīng)key的getter方法且沒有找到對(duì)應(yīng)key的屬性時(shí)調(diào)用- (id)valueForUndefinedKey:(NSString *)key{    if (!key || [key isEqualToString:@''])        return nil;    return [_mPropertiesDict valueForKey:key];}@end


然后執(zhí)行代碼:


LXCar *car = [[LXCar alloc] init];[car setValue:@'保時(shí)捷 卡宴 3.0T 鉑金版' forKey:@'name'];[car setValue:@'保時(shí)捷' forKey:@'brand'];[car setValue:@'卡宴' forKey:@'categroy'];NSLog(@'car name = %@, car brand = %@, categroy = %@', [car valueForKey:@'name'], [car valueForKey:@'brand'], [car valueForKey:@'categroy']);


下面是執(zhí)行結(jié)果,你會(huì)發(fā)現(xiàn)原本空空的LXCar類被我們利用KVC特性打造成了萬能的容器,可以放下原本沒有的name/brand/categroy屬性:




其實(shí)相信只要是耐著性子從頭看到現(xiàn)在的小伙伴們都能看的懂上面的代碼:利用接收對(duì)象既沒有相應(yīng)的setter/getter方法又無對(duì)象屬性時(shí)調(diào)用- (void)setValue:(id)value forUndefinedKey:(NSString *)key以及- (id)valueForUndefinedKey:(NSString *)key兩個(gè)方法的特性,給對(duì)象加入了一個(gè)可變字典作為填充屬性的區(qū)域?qū)崿F(xiàn)這樣一個(gè)萬能容器。


歸納kvc的優(yōu)缺點(diǎn)


看了文章上面所講的,你可能已經(jīng)愛上KVC了。但是請(qǐng)清醒一下,萬物都有兩面性,如果濫用KVC的話也不是什么好事:


  • KVC需要解析字符串來計(jì)算你所需要的答案,因此速度比較慢

  • 編輯器無法對(duì)KVC進(jìn)行錯(cuò)誤檢查,當(dāng)你的key鍵輸入錯(cuò)誤時(shí)會(huì)引起運(yùn)行時(shí)錯(cuò)誤


寫在最后


就像本文前面說的一樣,這種萬能容器對(duì)象可以用在后臺(tái)接口平時(shí)還算規(guī)范但是偶爾會(huì)多返回一些出參的情況。所以不論是runtime還是KVC,是底層知識(shí)還是語言特性,一定要學(xué)以致用。畢竟空懂一腔理論知識(shí)卻沒有解決問題的能力學(xué)再多的東西也沒有用……




    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美做爰猛烈叫床大尺度| 在线视频免费看你懂的| 国产一区二区三区草莓av| 欧美胖熟妇一区二区三区| 国产欧美日韩精品成人专区| 熟女免费视频一区二区| 视频一区日韩经典中文字幕| 亚洲美女国产精品久久| 国产成人av在线免播放观看av | 日韩人妻一区二区欧美| 亚洲午夜av久久久精品| 福利新区一区二区人口| 日韩18一区二区三区| 欧美日韩最近中国黄片| 狠狠干狠狠操亚洲综合| 国产成人精品视频一区二区三区 | 久久成人国产欧美精品一区二区 | 久久综合亚洲精品蜜桃| 国产精品欧美一级免费| 91亚洲熟女少妇在线观看| 在线观看国产成人av天堂野外| 精品欧美日韩一二三区| 国产精品免费无遮挡不卡视频| 免费在线观看激情小视频| 日韩成人h视频在线观看| 蜜桃臀欧美日韩国产精品| 国产午夜福利不卡片在线观看| 亚洲中文字幕亲近伦片| 日本午夜免费福利视频| 国产精品香蕉一级免费| 免费人妻精品一区二区三区久久久| 亚洲中文字幕亲近伦片| 日韩一区二区三区在线欧洲| 午夜福利92在线观看| 日本福利写真在线观看| 国产又粗又爽又猛又黄的| 免费在线成人激情视频| 亚洲中文字幕视频在线观看| 暴力性生活在线免费视频| 国产精品二区三区免费播放心 | 国产精品福利一级久久|