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

前言

從今天開始,我們將要開始逐步接近OC的動態(tài)特性,慢慢揭開OC底層runtime系統的神秘面紗,超強的動態(tài)特性,是OC和一般面向對象的語言最明顯的區(qū)別,也是這門古老的語言最具魅力的地方,如果可以正確的利用動態(tài)特性,那么可以幫助我們方便的解決很多棘手的問題.

我們今天來看的呢,是runtime庫里非常有用的一組函數,Associated Object動態(tài)關聯對象.這個功能,能夠讓我們動態(tài)的對一個對象綁定相關聯的數據.

有了這個功能,我們不僅能夠為自己編寫的類添加屬性,還能夠為系統框架里的類動態(tài)添加我們需要的屬性,甚至能夠在分類里動態(tài)添加屬性.我們這就來看看這個方便又強大的功能吧.

Associated Object使用場景

我們都有這樣的經驗,我們希望在既有的類上添加新的屬性,通常情況下:

如果這個類是我們自己編寫的,那么我們就可以方便的在文件中添加對應的屬性就可以

如果這個類是系統框架的,而并非我們自己編寫的,那么,我們通常會采取集成該系統類,產生新的類,添加我們需要的方法和屬性

但是,很多時候,某個對象并不是我們產生,而是通過其它機制產生的,比如,系統為我們返回了一個系統類的實例,但是,我們卻希望在這個實例加上這個類原本并沒有的屬性,來記錄或存儲一些數據,在這個時候我們按照常規(guī)的方法就不好解決了.

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

相關函數

Associated Object的相關函數在runtime.h 文件中,使用前,我們需要先引入該庫.而該庫中和Associated Object相關的函數有三個:

  1. objc_setAssociatedObject:用來給對象動態(tài)綁定關聯對象(也就是添加相應屬性)
  2. objc_getAssociatedObject:用來讀取對某對象動態(tài)綁定的關聯對象(讀取相應屬性)
  3. objc_removeAssociatedObjects:這個函數是用來解除某對象的所有關聯對象這項操作會將該對象所有的關聯對象都全部刪除.使用時,我們要格外注意.

Associated Object存儲策略:

在調用objc_setAssociatedObject:函數時,我們需要設置關聯對象的存儲策略,這類似于property屬性的存儲策略關鍵字,這些存儲策略名稱從字面上就可以輕易的與property屬性的存儲策略關鍵字輕松匹配,相信大家一定可以選對的.我就不再一一舉例了.

Associated Object存儲策略 property屬性存儲策略關鍵字
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic, strong
OBJC_ASSOCIATION_COPY_NONATOMIC copy, nonatomic
OBJC_ASSOCIATION_RETAIN strong
OBJC_ASSOCIATION_COPY copy

示例

說了這么多,我們通過一個小小的例子,來感受下Associated Object的妙用吧

我們都有過這樣的經歷,我們需要在用戶進行過某些操作的時候觸發(fā)一個提醒框,即AlertView.

通常代碼會像這個樣子:


-(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");
    }
}

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

-(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");
        }
    }
}

這樣的代碼,不僅繁瑣冗長,并不利于我們的代碼可讀性和高內聚低耦合的設計原則

我們將要通過Associated Object方式,對該情況進行處理

大概思路為,在編寫alertView時為每一個alertView關聯一個處理Block,在代理方法中我們只要調用alertView關聯的處理block就可以了,這樣的代碼將會變得異常清晰,而且具有極高的可讀性我們一起來看一下吧:

我們需要先導入需要的文件,并聲明一個用來充當關聯Key的字符常量:


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

然后在編寫提示框的時候,我們需要編寫一個處理alertView的block,并和alertView進行關聯:


    -(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];
        }

這樣處理過得alertView中就會綁定一個處理的block了,接下來我們在alertview的代理方法中,僅僅需要將這個block取出并調用,就可以了:


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

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

總結

上面的這個例子只是一個Associated Object一個簡單使用,還有很多妙用等待大家發(fā)現,Associated Object之所以能夠動態(tài)的為實例添加關聯對象,這要依附于我們強大的運行時系統,這點大家要好好理解,最后雖然Associated Object非常好用,但是也不建議大家濫用,只有在別的方式都不可行的情況下才建議大家使用關聯對象處理,因為如果你的編碼有誤,產生問題將非常難于查找,因為編譯器并不能夠檢測出運行時才會關聯的對象的相關問題,對于關聯對象,編譯器是有心無力的,保證它的正確性只能我們人為去檢測驗證

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,552評論 19 139
  • 轉至元數據結尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 2,051評論 0 9
  • Objective-C作為面向對象編程,“對象”(object)就是“基本構造單元”(building block...
    Mark_Lin閱讀 409評論 0 1
  • ——作者 舞動人生 每個人自己 就是自己的天 相信自己的天 就是相信別人 他她只做自己 他她堅定向前 我們做別人...
    創(chuàng)造全新幸福生活閱讀 331評論 0 0
  • 第一次畫畫 等素描書回來堅持兩三個月素描 等開學來了入手水彩或者彩鉛
    芥末和芒果閱讀 230評論 0 1

友情鏈接更多精彩內容