Objective-C 動態(tài)實現(xiàn)

在 Objective-C 中系宫,我們偶爾會看到一個屬性被聲明為 @dynamic, 其實這個是在向編譯器保證,雖然現(xiàn)在這個屬性找不到 setter 和 getter 方法建车,但是在運行時會有可用的實現(xiàn)扩借,你編譯器不要自動幫我合成 ivar 了。我們可以使用 resolveinstancemethod: 方法 和 resolveClassMethod: 方法來動態(tài)提供方法實現(xiàn)缤至,那么 @dynamic 合成屬性的方法是怎么樣的呢潮罪? 我們這里使用一個 Demo 來說明這個過程。
這個 Demo 使用動態(tài)實現(xiàn)來為 NSMutableDictionary 中存儲的屬性動態(tài)創(chuàng)建獲取方法和設(shè)置方法领斥。

創(chuàng)建一個 Person 對象嫉到,該對象有 firstName 和 lastName 這兩個屬性。

// Person.h
@interface Person : NSObject
@property (nonatomic,copy) NSString *firstName;
@property (nonatomic,copy) NSString *lastName;
@end

接下來看 Person.m 文件

#import "Person.h"
#import <objc/runtime.h>

@interface Person ()
@property (nonatomic,strong) NSMutableDictionary *properties;
@end

@implementation Person
// @dynamic, 其實這個是在向編譯器保證月洛,雖然現(xiàn)在這個屬性找不到 setter 和 getter 方法何恶,
// 但是在運行時會有可用的實現(xiàn),你編譯器不要自動幫我合成 ivar 了
@dynamic firstName,lastName;

- (id)init{
    if (self = [super init]) {
        _properties = [[NSMutableDictionary alloc] init];
    }
    return self;
}

// getter 方法
static id propertyIMP(id self, SEL _cmd){
    return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}

// setter 方法
static void setPropertyIMP(id self,SEL _cmd, id aValue){
    id value = [aValue copy];
    // 使用 mutableCopy 而不是 copy
    NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
    // 刪除 “set”
    [key deleteCharactersInRange:NSMakeRange(0, 3)];
    // 刪除 “:”
    [key deleteCharactersInRange:NSMakeRange([key length] -1, 1)];
    // 將第一個字母變?yōu)樾?    NSString *firstC = [key substringToIndex:1];
    [key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstC lowercaseString]];
    // 保存對應(yīng)屬性的值
    [[self properties] setValue:value forKey:key];
}

// 這里假設(shè)所有不能識別的方法都是 setter 方法或者 getter 方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if ([NSStringFromSelector(sel) hasPrefix:@"set"]) {
        // 第一個字符 v 表明返回值是一個 void嚼黔。
        // 接下來的二個字符 @: 表明該方法接受一個 id 和一個 SEL
        // 最后一個字符是方法的顯式參數(shù) @ 表示是一個 id
        class_addMethod([self class], sel, (IMP)setPropertyIMP, "v@:@");
    }else{
        // 第一個字符 @ 表明返回值是一個 id细层。
        // 對于消息傳遞系統(tǒng)來說惜辑,所以的 Objective-C 對象都是 id 類型。
        // 接下來的二個字符 @: 表明該方法接受一個 id 和一個 SEL
        class_addMethod([self class], sel, (IMP)propertyIMP, "@:@");
    }
    return YES;
}
@end

從代碼中可以看到疫赎,我們將 firstName,lastName 這2個屬性設(shè)置成 @dynamic 韵丑。然后提供了 static void setPropertyIMP(id self,SEL _cmd, id aValue) 這個 setter 方法,也提供了 static id propertyIMP(id self, SEL _cmd) 這個 getter 方法虚缎。在 setter 和 getter 中使用了 NSMutableDictionary 來存儲和讀取屬性。

當(dāng) Person 無法識別一些方法的時候钓株,Objective-C 的消息分派就會調(diào)用 Person 類的 + (BOOL)resolveInstanceMethod:(SEL)sel 方法实牡。那么我們在這個方法里面 為 Person 這個類動態(tài)的添加屬性的 setter 和 getter 方法。這樣 Person 就可以正確的響應(yīng)屬性的 setter 和 getter创坞。這個就是 Objective-C 的動態(tài)實現(xiàn),在運行過程中提供方法實現(xiàn)题涨。

參考

本文是《iOS 編程實戰(zhàn)》的讀書筆記,對閱讀的內(nèi)容進(jìn)行總結(jié)纲堵。當(dāng)我們看懂了之后,不一定懂闰渔;我們跟著書上代碼敲了一遍之后席函,還是不一定懂;只有我們能夠把自己理解的內(nèi)容寫下來或者通過其它方式表達(dá)出來的時候冈涧,這個才是真的懂了;

Runtime Type Encoding
《iOS編程實戰(zhàn)》第24章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末营曼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子愚隧,更是在濱河造成了極大的恐慌蒂阱,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,294評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狂塘,死亡現(xiàn)場離奇詭異,居然都是意外死亡睹耐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評論 3 385
  • 文/潘曉璐 我一進(jìn)店門响委,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赘风,你說我怎么就攤上這事⊙裕” “怎么了荸哟?”我有些...
    開封第一講書人閱讀 157,790評論 0 348
  • 文/不壞的土叔 我叫張陵鞍历,是天一觀的道長。 經(jīng)常有香客問我劣砍,道長扇救,這世上最難降的妖魔是什么刑枝? 我笑而不...
    開封第一講書人閱讀 56,595評論 1 284
  • 正文 為了忘掉前任迅腔,我火速辦了婚禮,結(jié)果婚禮上洁灵,老公的妹妹穿的比我還像新娘掺出。我一直安慰自己徽千,他們只是感情好汤锨,可當(dāng)我...
    茶點故事閱讀 65,718評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闲礼,像睡著了一般牍汹。 火紅的嫁衣襯著肌膚如雪柬泽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評論 1 290
  • 那天锨并,我揣著相機與錄音,去河邊找鬼解幼。 笑死抑党,一個胖子當(dāng)著我的面吹牛撵摆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播特铝,決...
    沈念sama閱讀 39,053評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼鲫剿,長吁一口氣:“原來是場噩夢啊……” “哼鳄逾!你這毒婦竟也來了牵素?” 一聲冷哼從身側(cè)響起澄者,我...
    開封第一講書人閱讀 37,797評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赠幕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榕堰,經(jīng)...
    沈念sama閱讀 44,250評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡嫌套,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,570評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了魏蔗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,711評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡莺治,死狀恐怖帚稠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滋早,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評論 4 332
  • 正文 年R本政府宣布瘟判,位于F島的核電站怨绣,受9級特大地震影響拷获,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匆瓜,卻給世界環(huán)境...
    茶點故事閱讀 40,018評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茧妒。 院中可真熱鬧左冬,春花似錦桐筏、人聲如沸拇砰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踱葛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尸诽,已是汗流浹背盯另。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留土铺,地道東北人。 一個月前我還...
    沈念sama閱讀 46,461評論 2 360
  • 正文 我出身青樓悲敷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親后德。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,595評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉理张,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評論 0 9
  • 面試筆試都是必考語法知識的雾叭。請認(rèn)真復(fù)習(xí)和深入研究OC悟耘。 Objective-C 方法和選擇器有何不同织狐?(Diffe...
    b485c88ab697閱讀 5,683評論 0 35
  • 前言:面試筆試都是必考語法知識點。請認(rèn)真復(fù)習(xí)和深入研究OC移迫。 目錄:iOS-面試題-OC基礎(chǔ)篇 (1) - (84...
    麥穗0615閱讀 4,251評論 0 33
  • 柚子小姐今年二十五,她說“我失戀了”的時候邪媳,就像喝了口白開水那樣自然。 可是雨效,聽她講出這句話的所有人,都像吃了口芥...
    西涼姑娘閱讀 500評論 1 1
  • 復(fù)盤計劃:10?下旬重點 計劃和復(fù)盤的完成? 紅色標(biāo)記每天完成一點點 10點 上課 1點到4點開會 5點面談2個學(xué)...
    從心印心閱讀 387評論 0 0