動(dòng)態(tài)添加屬性-Associated Object

前言

從今天開(kāi)始,我們將要開(kāi)始逐步接近OC的動(dòng)態(tài)特性,慢慢揭開(kāi)OC底層runtime系統(tǒng)的神秘面紗,超強(qiáng)的動(dòng)態(tài)特性,是OC和一般面向?qū)ο蟮恼Z(yǔ)言最明顯的區(qū)別,也是這門(mén)古老的語(yǔ)言最具魅力的地方,如果可以正確的利用動(dòng)態(tài)特性,那么可以幫助我們方便的解決很多棘手的問(wèn)題.

我們今天來(lái)看的呢,是runtime庫(kù)里非常有用的一組函數(shù),Associated Object動(dòng)態(tài)關(guān)聯(lián)對(duì)象.這個(gè)功能,能夠讓我們動(dòng)態(tài)的對(duì)一個(gè)對(duì)象綁定相關(guān)聯(lián)的數(shù)據(jù).

有了這個(gè)功能,我們不僅能夠?yàn)樽约壕帉?xiě)的類(lèi)添加屬性,還能夠?yàn)橄到y(tǒng)框架里的類(lèi)動(dòng)態(tài)添加我們需要的屬性,甚至能夠在分類(lèi)里動(dòng)態(tài)添加屬性.我們這就來(lái)看看這個(gè)方便又強(qiáng)大的功能吧.

Associated Object使用場(chǎng)景

我們都有這樣的經(jīng)驗(yàn),我們希望在既有的類(lèi)上添加新的屬性,通常情況下:

如果這個(gè)類(lèi)是我們自己編寫(xiě)的,那么我們就可以方便的在文件中添加對(duì)應(yīng)的屬性就可以

如果這個(gè)類(lèi)是系統(tǒng)框架的,而并非我們自己編寫(xiě)的,那么,我們通常會(huì)采取集成該系統(tǒng)類(lèi),產(chǎn)生新的類(lèi),添加我們需要的方法和屬性

但是,很多時(shí)候,某個(gè)對(duì)象并不是我們產(chǎn)生,而是通過(guò)其它機(jī)制產(chǎn)生的,比如,系統(tǒng)為我們返回了一個(gè)系統(tǒng)類(lèi)的實(shí)例,但是,我們卻希望在這個(gè)實(shí)例加上這個(gè)類(lèi)原本并沒(méi)有的屬性,來(lái)記錄或存儲(chǔ)一些數(shù)據(jù),在這個(gè)時(shí)候我們按照常規(guī)的方法就不好解決了.

這時(shí),我們的Associated Object就要發(fā)揮它的作用了.

相關(guān)函數(shù)

Associated Object的相關(guān)函數(shù)在runtime.h 文件中,使用前,我們需要先引入該庫(kù).而該庫(kù)中和Associated Object相關(guān)的函數(shù)有三個(gè):

  1. objc_setAssociatedObject:用來(lái)給對(duì)象動(dòng)態(tài)綁定關(guān)聯(lián)對(duì)象(也就是添加相應(yīng)屬性)
  2. objc_getAssociatedObject:用來(lái)讀取對(duì)某對(duì)象動(dòng)態(tài)綁定的關(guān)聯(lián)對(duì)象(讀取相應(yīng)屬性)
  3. objc_removeAssociatedObjects:這個(gè)函數(shù)是用來(lái)解除某對(duì)象的所有關(guān)聯(lián)對(duì)象這項(xiàng)操作會(huì)將該對(duì)象所有的關(guān)聯(lián)對(duì)象都全部刪除.使用時(shí),我們要格外注意.

Associated Object存儲(chǔ)策略:

在調(diào)用objc_setAssociatedObject:函數(shù)時(shí),我們需要設(shè)置關(guān)聯(lián)對(duì)象的存儲(chǔ)策略,這類(lèi)似于property屬性的存儲(chǔ)策略關(guān)鍵字,這些存儲(chǔ)策略名稱(chēng)從字面上就可以輕易的與property屬性的存儲(chǔ)策略關(guān)鍵字輕松匹配,相信大家一定可以選對(duì)的.我就不再一一舉例了.

Associated Object存儲(chǔ)策略 property屬性存儲(chǔ)策略關(guān)鍵字
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic, strong
OBJC_ASSOCIATION_COPY_NONATOMIC copy, nonatomic
OBJC_ASSOCIATION_RETAIN strong
OBJC_ASSOCIATION_COPY copy

示例

說(shuō)了這么多,我們通過(guò)一個(gè)小小的例子,來(lái)感受下Associated Object的妙用吧

我們都有過(guò)這樣的經(jīng)歷,我們需要在用戶(hù)進(jìn)行過(guò)某些操作的時(shí)候觸發(fā)一個(gè)提醒框,即AlertView.

通常代碼會(huì)像這個(gè)樣子:


-(void)click
{
    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"alert" message:@"msg" delegate:self cancelButtonTitle:@"cancle" otherButtonTitles:@"confirm", nil];
    
    [alert show];
}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex==0) {
        NSLog(@"do someThing");
    }else
    {
        NSLog(@"do otherThing");
    }
}

但是經(jīng)常我們會(huì)在一個(gè)控制器中有多個(gè)潛在將會(huì)觸發(fā)的提醒框,如果是這樣,那么我們通常會(huì)為alertView指定tag,在代理方法里區(qū)分不同的提醒框,做不同處理,那么代碼就會(huì)變成這個(gè)樣子.

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    
    if (alertView.tag==0) {
        if (buttonIndex==0) {
            NSLog(@"do someThing");
        }else
        {
            NSLog(@"do otherThing");
        }
    }else if (alertView.tag==1)
    {
        if (buttonIndex==0) {
            NSLog(@"do someThing");
        }else
        {
            NSLog(@"do otherThing");
        }
        
    }else if (alertView.tag==2)
    {
        if (buttonIndex==0) {
            NSLog(@"do someThing");
        }else
        {
            NSLog(@"do otherThing");
        }
    }else if (alertView.tag==3)
    {
        if (buttonIndex==0) {
            NSLog(@"do someThing");
        }else
        {
            NSLog(@"do otherThing");
        }
    }
}

這樣的代碼,不僅繁瑣冗長(zhǎng),并不利于我們的代碼可讀性和高內(nèi)聚低耦合的設(shè)計(jì)原則

我們將要通過(guò)Associated Object方式,對(duì)該情況進(jìn)行處理

大概思路為,在編寫(xiě)alertView時(shí)為每一個(gè)alertView關(guān)聯(lián)一個(gè)處理Block,在代理方法中我們只要調(diào)用alertView關(guān)聯(lián)的處理block就可以了,這樣的代碼將會(huì)變得異常清晰,而且具有極高的可讀性我們一起來(lái)看一下吧:

我們需要先導(dǎo)入需要的文件,并聲明一個(gè)用來(lái)充當(dāng)關(guān)聯(lián)Key的字符常量:


     #import <objc/runtime.h>
     
     static char const alertDealBlockKey;
  

然后在編寫(xiě)提示框的時(shí)候,我們需要編寫(xiě)一個(gè)處理alertView的block,并和alertView進(jìn)行關(guān)聯(lián):


    -(void)click
    {
        UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"alert" message:@"msg" delegate:self cancelButtonTitle:@"cancle" otherButtonTitles:@"confirm", nil];
        
        
        void (^alertDealBlock)(NSInteger btnIndex)=^(NSInteger btnIndex){
          
            if (btnIndex==0) {
                NSLog(@"do someThing");
            }else
            {
                NSLog(@"do otherThing");
            }
        };
        
        objc_setAssociatedObject(alert, &alertDealBlockKey, alertDealBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
        [alert show];
        }

這樣處理過(guò)得alertView中就會(huì)綁定一個(gè)處理的block了,接下來(lái)我們?cè)赼lertview的代理方法中,僅僅需要將這個(gè)block取出并調(diào)用,就可以了:


    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        void (^alertDealBlock)(NSInteger btnIndex)=objc_getAssociatedObject(alertView, &alertDealBlockKey);
        
        alertDealBlock(buttonIndex);
        
    }

這樣無(wú)論該文件中將有多少個(gè)alertView,我們的代理方法中也只需要這樣短短兩行的代碼就可以處理,是不是很簡(jiǎn)單呢,而且,在編寫(xiě)alertView的時(shí)候我們就可以順便把處理方式編寫(xiě)好,可讀性也大大提高,是不是還是很優(yōu)雅的呢?

總結(jié)

上面的這個(gè)例子只是一個(gè)Associated Object一個(gè)簡(jiǎn)單使用,還有很多妙用等待大家發(fā)現(xiàn),Associated Object之所以能夠動(dòng)態(tài)的為實(shí)例添加關(guān)聯(lián)對(duì)象,這要依附于我們強(qiáng)大的運(yùn)行時(shí)系統(tǒng),這點(diǎn)大家要好好理解,最后雖然Associated Object非常好用,但是也不建議大家濫用,只有在別的方式都不可行的情況下才建議大家使用關(guān)聯(lián)對(duì)象處理,因?yàn)槿绻愕木幋a有誤,產(chǎn)生問(wèn)題將非常難于查找,因?yàn)榫幾g器并不能夠檢測(cè)出運(yùn)行時(shí)才會(huì)關(guān)聯(lián)的對(duì)象的相關(guān)問(wèn)題,對(duì)于關(guān)聯(lián)對(duì)象,編譯器是有心無(wú)力的,保證它的正確性只能我們?nèi)藶槿z測(cè)驗(yàn)證

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市摩渺,隨后出現(xiàn)的幾起案子简烤,更是在濱河造成了極大的恐慌,老刑警劉巖摇幻,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件横侦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绰姻,警方通過(guò)查閱死者的電腦和手機(jī)枉侧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狂芋,“玉大人榨馁,你說(shuō)我怎么就攤上這事≈姆” “怎么了翼虫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)屡萤。 經(jīng)常有香客問(wèn)我蛙讥,道長(zhǎng),這世上最難降的妖魔是什么灭衷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任次慢,我火速辦了婚禮,結(jié)果婚禮上翔曲,老公的妹妹穿的比我還像新娘迫像。我一直安慰自己,他們只是感情好瞳遍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布闻妓。 她就那樣靜靜地躺著,像睡著了一般掠械。 火紅的嫁衣襯著肌膚如雪由缆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天猾蒂,我揣著相機(jī)與錄音均唉,去河邊找鬼。 笑死肚菠,一個(gè)胖子當(dāng)著我的面吹牛舔箭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼层扶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼箫章!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起镜会,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤檬寂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后戳表,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體桶至,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年扒袖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亩码。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡季率,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出描沟,到底是詐尸還是另有隱情飒泻,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布吏廉,位于F島的核電站泞遗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏席覆。R本人自食惡果不足惜史辙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佩伤。 院中可真熱鬧聊倔,春花似錦、人聲如沸生巡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)孤荣。三九已至甸陌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盐股,已是汗流浹背钱豁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疯汁,地道東北人寥院。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像涛目,于是被迫代替她去往敵國(guó)和親秸谢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凛澎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)估蹄,斷路器塑煎,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評(píng)論 0 9
  • Objective-C作為面向?qū)ο缶幊汤湮荆皩?duì)象”(object)就是“基本構(gòu)造單元”(building block...
    Mark_Lin閱讀 330評(píng)論 0 1
  • ——作者 舞動(dòng)人生 每個(gè)人自己 就是自己的天 相信自己的天 就是相信別人 他她只做自己 他她堅(jiān)定向前 我們做別人...
    創(chuàng)造全新幸福生活閱讀 285評(píng)論 0 0
  • 第一次畫(huà)畫(huà) 等素描書(shū)回來(lái)堅(jiān)持兩三個(gè)月素描 等開(kāi)學(xué)來(lái)了入手水彩或者彩鉛
    芥末和芒果閱讀 202評(píng)論 0 1