runtime之關(guān)聯(lián)的用法

個人學(xué)習(xí)心得

關(guān)聯(lián)是指把兩個對象互相關(guān)聯(lián)起來,使得其中的一個對象作為另外一個對象的一部分.我們可以在不修改類的定義的情況下為其對象增加存儲空間.
關(guān)聯(lián)對象類似于成員變量,是在運(yùn)行時(shí)添加的.當(dāng)我們給一個分類添加新的成員變量時(shí),編譯器會報(bào)錯,這個問題可以通過添加全局變量來解決,但這些都不是Ivar,因?yàn)樗麄儾粫B接到一個單獨(dú)的實(shí)例.關(guān)聯(lián)就可以很方便的解決這個問題

  • 運(yùn)行時(shí)中關(guān)聯(lián)的函數(shù)有三個
// 用一個給定的key給一個指定對象設(shè)置一個關(guān)聯(lián)的值和關(guān)聯(lián)策略
void objc_setAssociatedObject(id object, constvoid *key, id value, objc_AssociationPolicy policy)

object:源對象,即被關(guān)聯(lián)的對象
key:關(guān)聯(lián)的關(guān)鍵字,是一個void類型的指針.這個關(guān)鍵字建議是唯一的,如果使用同一個key來關(guān)聯(lián)另外一個對象時(shí),之前關(guān)聯(lián)的對象會被自動釋放.
value:關(guān)聯(lián)的對象.當(dāng)value為nil的時(shí)候,可以移除相應(yīng)的關(guān)聯(lián)
policy:關(guān)聯(lián)策略,是個枚舉值.用來表名關(guān)聯(lián)的對象是copy, retain還是assign方式進(jìn)行的,copy和retain有原子和非原子.和聲明屬性很類似.
// 從一個指定對象的給定key獲取相關(guān)聯(lián)的對象

id objc_getAssociatedObject(id object, const void*key)

object:被關(guān)聯(lián)的對象
key:關(guān)聯(lián)的關(guān)鍵字
// 斷開所有的關(guān)聯(lián)  通常情況下不建議使用這個函數(shù)违寿,因?yàn)樗麜嚅_所有關(guān)聯(lián)胳施。只有在需要把對象恢復(fù)到“原始狀態(tài)”的時(shí)候才會使用這個函數(shù)

void objc_removeAssociatedObjects(id object)

object:被關(guān)聯(lián)的對象
  • 具體的使用 demo(myruntime)
  • 1.給一個分類添加屬性(關(guān)聯(lián)成員變量)
        #import <Foundation/Foundation.h>

         @interface NSObject (Runtime)

         /** 添加屬性 */
         @property (nonatomic, copy) NSString*runtimeName;
         @property (nonatomic, assign) float weight;
         @end

        

         #import "NSObject+Runtime.h"
         #import <objc/runtime.h>

         @implementation NSObject (Runtime)

         static char *myKey;
         #pragma mark - 設(shè)置setter和getter方法

         - (void)setRuntimeName:(NSString*)runtimeName{

             objc_setAssociatedObject(self, myKey, runtimeName, OBJC_ASSOCIATION_COPY);

         }
         - (NSString *)runtimeName{

             return objc_getAssociatedObject(self,myKey);

         }
         - (void)setWeight:(float)weight{

             objc_setAssociatedObject(self,@selector(weight), @(weight), OBJC_ASSOCIATION_ASSIGN);

         }

         - (float)weight{
             return [objc_getAssociatedObject(self,_cmd) floatValue];

         }

         @end
  • 2.動態(tài)的添加一個手勢到UIView上
        #import <UIKit/UIKit.h>

         @interface UIView (Block)

         // 添加點(diǎn)擊事件,用block回調(diào)
         - (void)tapActionWithBlock:(void(^)(void))block;
         @end

        

        

        #import "UIView+Block.h"
         #import <objc/runtime.h>

         @interface UIView ()

         @end

         // 關(guān)鍵字
         static char blockKey;
         static char tapKey;
         @implementation UIView (Block)

         #pragma mark - 添加點(diǎn)擊事件
         - (void)tapActionWithBlock:(void(^)(void))block{
             UITapGestureRecognizer *tap =objc_getAssociatedObject(self, &tapKey);
             if (!tap) {
                 tap = [[UITapGestureRecognizer alloc]initWithTarget:selfaction:@selector(handleActionForTap:)];
                 [self addGestureRecognizer:tap];
                 objc_setAssociatedObject(self, &tapKey, tap, OBJC_ASSOCIATION_RETAIN);
             }
             objc_setAssociatedObject(self, &blockKey, block, OBJC_ASSOCIATION_COPY);
         }

    
         // 點(diǎn)擊事件回調(diào)

         - (void)handleActionForTap:(UITapGestureRecognizer *)tap{
             if (tap.state ==UIGestureRecognizerStateRecognized) {
                 void(^block)(void) =objc_getAssociatedObject(self, &blockKey);
                 if (block) {
                     block();
                 }
             }
         }
        

         @end

  • 3.給UIAlertView添加一個類方法
        #import <UIKit/UIKit.h>
         typedef void(^AlertViewCallBackBlock)(NSInteger buttonIndex);

         @interface UIAlertView (runtime)

         // 定義回調(diào)block
         @property (nonatomic, copy)AlertViewCallBackBlock callBackBlock;

         + (void)alertViewCallBack:(AlertViewCallBackBlock)callBack WithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancel otherButtonTitles:(NSString *)otherTitle, ...;

         @end

         #import "UIAlertView+runtime.h"
         #import <objc/runtime.h>

         @implementation UIAlertView (runtime)

         // 設(shè)置關(guān)聯(lián)
         - (void)setCallBackBlock:(AlertViewCallBackBlock)callBackBlock{
             objc_setAssociatedObject(self,@selector(callBackBlock), callBackBlock,OBJC_ASSOCIATION_COPY_NONATOMIC);
         }

         - (AlertViewCallBackBlock)callBackBlock{
             return objc_getAssociatedObject(self,_cmd);
         }

         + (void)alertViewCallBack:(AlertViewCallBackBlock)callBack WithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancel otherButtonTitles:(NSString *)otherTitle, ...{
             UIAlertView *alertView = [[UIAlertViewalloc] initWithTitle:title message:messagedelegate:nil cancelButtonTitle:cancelotherButtonTitles:otherTitle, nil];
             NSString *other = nil;
             va_list args;
             if (otherTitle) {
                 va_start(args, otherTitle);
                 while ((other = va_arg(args, NSString*))) {
                     [alertViewaddButtonWithTitle:other];
                 }
                 va_end(args);
             }
             alertView.delegate = alertView;
             [alertView show];
             alertView.callBackBlock = callBack;
         }
         - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
             if (self.callBackBlock) {
                 self.callBackBlock(buttonIndex);
             }
         }
         @end

          // 說明:
          va_list, va_start, va_arg, va_end用于C語言的可變參數(shù)

          va_list:用來定義一個指向參數(shù)的指針

          va_start(ap, param):初始化va_list定義的變量.apap是va_list定義的變量,param是參數(shù)數(shù)組.初始化后,VA_LIST指針指向第二個參數(shù)

          va_arg(ap, type):返回可變參數(shù),ap是va_list定義的變量,type是要返回參數(shù)的類型

          va_end(ap):結(jié)束可變參數(shù)的獲取,ap是va_list定義的變量,

          獲取可變參數(shù)時(shí)用的是while循環(huán),所以數(shù)組中最后一個參數(shù)需要傳入nil作為結(jié)束遍歷的標(biāo)識.    
  • 4.給UIActionSheet添加一個類方法

         #import <UIKit/UIKit.h>
         typedef void(^ActionSheetCallBackBlock)(NSInteger buttonIndex);
         @interface UIActionSheet (runtime)

         // 定義回調(diào)block
         @property (nonatomic, copy)ActionSheetCallBackBlock callBackBlock;

         + (void)actionSheetCallBlock:(ActionSheetCallBackBlock)callBackBlock withTitle:(NSString *)title message:(NSString*)message cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitles:(NSString*)otherTitles, ...;

         @end

        

 

        #import "UIActionSheet+runtime.h"
        #import <objc/runtime.h>
        @implementation UIActionSheet (runtime)

      - (void)setCallBackBlock:(ActionSheetCallBackBlock)callBackBlock{

              objc_setAssociatedObject(self,@selector(callBackBlock),      callBackBlock,OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (ActionSheetCallBackBlock)callBackBlock{
    return objc_getAssociatedObject(self, _cmd);
}

+ (void)actionSheetCallBlock:(ActionSheetCallBackBlock)callBackBlock withTitle:(NSString *)title message:(NSString*)message cancelButtonTitle:(NSString*)cancelButtonTitle otherButtonTitles:(NSString*)otherTitles, ...{
    UIActionSheet *actionSheet = [[UIActionSheetalloc] initWithTitle:title delegate:nilcancelButtonTitle:cancelButtonTitledestructiveButtonTitle:nilotherButtonTitles:otherTitles, nil];
    NSString *other = nil;
    va_list args;
    if (otherTitles) {
        va_start(args, otherTitles);
        while ((other = va_arg(args, NSString*))) {
            [actionSheetaddButtonWithTitle:other];
        }
        va_end(args);
    }
    actionSheet.callBackBlock = callBackBlock;
    actionSheet.delegate = actionSheet;
    [actionSheet showInView:[UIApplicationsharedApplication].keyWindow];
}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (self.callBackBlock) {
        self.callBackBlock(buttonIndex);
    }
}

@end
  • 5.對UIButton的點(diǎn)擊事件也可以做一個封裝,在開發(fā)中可以減少很多重復(fù)的代碼
#import <UIKit/UIKit.h>
typedef void(^TouchUpInsideBlock)();
@interface UIButton (Runtime)
- (void)touchUpInsideBlock:(TouchUpInsideBlock)touchBlock;
@end

#import "UIButton+Runtime.h"
#import <objc/runtime.h>
const char *ggTouchBlock;

@implementation UIButton (Runtime)

- (void)touchUpInsideBlock:(TouchUpInsideBlock)touchBlock{
    if (touchBlock) {
        objc_setAssociatedObject(self,ggTouchBlock, touchBlock,OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
  [self addTarget:selfaction:@selector(clickButton)forControlEvents:UIControlEventTouchUpInside];
}

- (void)clickButton{
    TouchUpInsideBlock touchBlock =objc_getAssociatedObject(self, ggTouchBlock);
    if (touchBlock) {
        touchBlock();
    }
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末供置,一起剝皮案震驚了整個濱河市进鸠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碱屁,老刑警劉巖磷脯,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異娩脾,居然都是意外死亡赵誓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門晦雨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來架曹,“玉大人,你說我怎么就攤上這事闹瞧“笮郏” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵奥邮,是天一觀的道長万牺。 經(jīng)常有香客問我,道長洽腺,這世上最難降的妖魔是什么脚粟? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蘸朋,結(jié)果婚禮上核无,老公的妹妹穿的比我還像新娘。我一直安慰自己藕坯,他們只是感情好团南,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布噪沙。 她就那樣靜靜地躺著,像睡著了一般吐根。 火紅的嫁衣襯著肌膚如雪正歼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天拷橘,我揣著相機(jī)與錄音局义,去河邊找鬼。 笑死冗疮,一個胖子當(dāng)著我的面吹牛萄唇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赌厅,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼穷绵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了特愿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤勾缭,失蹤者是張志新(化名)和其女友劉穎揍障,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俩由,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毒嫡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幻梯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜畸。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖碘梢,靈堂內(nèi)的尸體忽然破棺而出咬摇,到底是詐尸還是另有隱情,我是刑警寧澤煞躬,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布肛鹏,位于F島的核電站,受9級特大地震影響恩沛,放射性物質(zhì)發(fā)生泄漏在扰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一雷客、第九天 我趴在偏房一處隱蔽的房頂上張望芒珠。 院中可真熱鬧,春花似錦搅裙、人聲如沸皱卓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽好爬。三九已至局雄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間存炮,已是汗流浹背炬搭。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留穆桂,地道東北人宫盔。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像享完,于是被迫代替她去往敵國和親灼芭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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