Runtime學(xué)習(xí)筆記(統(tǒng)計(jì)用戶行為)

前言

最近公司在做一個用戶行為統(tǒng)計(jì),現(xiàn)在這家公司是一家金融公司,想統(tǒng)計(jì)一些用戶行為,比如用戶輸入身份證的時間,次數(shù),是否拷貝等等,通過這個使用相應(yīng)的算法,結(jié)合用戶的一些信用資料來對用戶的額度以及還款能力做一些決策,目前有兩種方案:1,通過子父類實(shí)現(xiàn);2,通過分類實(shí)現(xiàn).這二者各有優(yōu)點(diǎn),也有缺點(diǎn),最后選擇的方案應(yīng)該是子父類繼承的方案,這篇文章編寫的目的主要在于記錄一下使用分類時用到的runtime的一些技巧,方便日后學(xué)習(xí)和使用.

好文章記載

  • 1方法替換/攔截,給分類(對象)動態(tài)綁定屬性,獲得一個類的所有屬性,方法,實(shí)現(xiàn)NSCoding自動歸檔解檔,模型和字典的自動轉(zhuǎn)換:鏈接.

  • 2Runtime一些數(shù)據(jù)類型名稱的解釋:鏈接

  • 3使用Runtime做到根據(jù)后臺返回做到跳轉(zhuǎn)不同界面:鏈接

  • 4冰大的Runtime文章,偏底層:鏈接

用戶行為統(tǒng)計(jì)分類的一個簡單實(shí)現(xiàn)

基本上看文章一就好了,基本能滿足日常使用的一般需求了.其他的有需求的話可以仔細(xì)看看

代碼:

頭文件

#import <UIKit/UIKit.h>

    @interface UIButton (category)

    //獲取button的點(diǎn)擊次數(shù)
    @property (nonatomic, assign) NSInteger btnClickedCount;

    @property (nonatomic, copy) void (^currentActionBlock)() ;

    @end

實(shí)現(xiàn)文件

#import "UIButton+category.h"

    #import <objc/runtime.h>
    #import <objc/message.h>

    NSString * const fy_btnClickedCountKey = nil;
    NSString * const fy_btnCurrentActionBlockKey = nil;

    @implementation UIButton (category)

    + (void)load{
        
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
            //SEL是selector在Objc中的表示類型
            SEL origilaSEL = @selector(addTarget:action:forControlEvents:);
            SEL hookSEL = @selector(fy_addTarget:action:forControlEvents:);
            
            //交換方法
            //class_getInstanceMethod獲取對象方法,class_getClassMethod獲取類方法
            Method origilalMethod = class_getInstanceMethod(self, origilaSEL);
            Method hookMethod = class_getInstanceMethod(self, hookSEL);
            
            //可以直接用這一句交換不用下面的方法
    //        method_exchangeImplementations(origilalMethod, hookMethod);
            
            
            /**
             動態(tài)添加方法

             @param self 給哪個類添加方法
             @param origilaSEL 添加方法的方法編號(方法名字)
             @param self 實(shí)現(xiàn)這個方法的函數(shù)
             @param origilaSEL 一個定義該函數(shù)返回值類型和參數(shù)類型的字符串
             @return <#return value description#>
             */
            class_addMethod(self, origilaSEL, class_getMethodImplementation(self, origilaSEL), method_getTypeEncoding(origilalMethod));
            class_addMethod(self, hookSEL, class_getMethodImplementation(self, hookSEL), method_getTypeEncoding(hookMethod));
            
            method_exchangeImplementations(class_getInstanceMethod(self, origilaSEL), class_getInstanceMethod(self, hookSEL));
            
        });
    }

    - (void)fy_addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{
        
        __weak typeof(target) weakTarget = target;
        __weak typeof(self) weakSelf  = self;
        
        //利用 關(guān)聯(lián)對象 給UIButton 增加了一個 block
        if (action) {
            
            [self  setCurrentActionBlock:^{
                @try {
                    ((void (*)(void *, SEL,  typeof(weakSelf) ))objc_msgSend)((__bridge void *)(weakTarget), action , weakSelf);
                } @catch (NSException *exception) {
                } @finally {
                }
                
            }];
        }
        
        //發(fā)送消息 其實(shí)是本身  要執(zhí)行的action 先執(zhí)行,寫下來的 fy_clicked:方法
        //為什么這么寫而不是用官方的方法呢?因?yàn)榻?jīng)過上面的方法交換,下面的這個方法已經(jīng)相當(dāng)于系統(tǒng)的addTarget方法了,如果再使用addTarget那么是無法使用系統(tǒng)的方法了
        [self fy_addTarget:self action:@selector(fy_clicked:) forControlEvents:controlEvents];
    }

    //攔截了按鈕點(diǎn)擊后要執(zhí)行的代碼
    - (void)fy_clicked:(UIButton *)sender{
        //統(tǒng)計(jì) 在這個方法中執(zhí)行想要操作的
        
        self.btnClickedCount++;
        
        NSLog(@"%@ 點(diǎn)擊 %ld次 ",[sender titleForState:UIControlStateNormal], self.btnClickedCount);
        
        //執(zhí)行原來要執(zhí)行的方法
        sender.currentActionBlock();
    }

    //增加一個 block 關(guān)聯(lián)UIButton
    - (void)setCurrentActionBlock:(void (^)())currentActionBlock{
        
        objc_setAssociatedObject(self, &fy_btnCurrentActionBlockKey, currentActionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }

    - (void (^)())currentActionBlock{
        return objc_getAssociatedObject(self, &fy_btnCurrentActionBlockKey);
    }

    #pragma mark -統(tǒng)計(jì)
    //在分類中增加了 btnClickedCount的 (setter 和 getter)方法殖演,使用關(guān)聯(lián)對象增加了相關(guān)的成員空間,注意這里的名字必須符合蘋果那一套命名規(guī)則
    - (NSInteger)btnClickedCount{
        //根據(jù)關(guān)聯(lián)的key獲取到關(guān)聯(lián)的值
        id tmp = objc_getAssociatedObject(self, &fy_btnClickedCountKey);
        NSNumber *number = tmp;
        return number.integerValue;
    }


    - (void)setBtnClickedCount:(NSInteger)btnClickedCount{
        
        /**
         添加關(guān)聯(lián)

         @param self 給哪個對象添加關(guān)聯(lián)
         @param fy_btnClickedCountKey 關(guān)聯(lián)的key,通過這個key獲取
         @param btnClickedCount 關(guān)聯(lián)的值
         @param OBJC_ASSOCIATION_ASSIGN關(guān)聯(lián)的策略
         @return <#return value description#>
         */
        objc_setAssociatedObject(self, &fy_btnClickedCountKey, @(btnClickedCount), OBJC_ASSOCIATION_ASSIGN);
    }
    @end

關(guān)聯(lián)策略

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                        *   The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                        *   The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                        *   The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                        *   The association is made atomically. */
};

OBJC_ASSOCIATION_ASSIGN    指定關(guān)聯(lián)對象的弱引用
OBJC_ASSOCIATION_RETAIN_NONATOMIC  指定關(guān)聯(lián)對象的強(qiáng)引用,這個關(guān)聯(lián)不是原子性的
OBJC_ASSOCIATION_COPY_NONATOMIC  指定復(fù)制關(guān)聯(lián)的對象,這個關(guān)聯(lián)不是原子性的
OBJC_ASSOCIATION_RETAIN  指定關(guān)聯(lián)對象的強(qiáng)引用,這個關(guān)聯(lián)是原子性的
OBJC_ASSOCIATION_COPY  指定復(fù)制關(guān)聯(lián)的對象,這個關(guān)聯(lián)是原子性的
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市年鸳,隨后出現(xiàn)的幾起案子趴久,更是在濱河造成了極大的恐慌,老刑警劉巖搔确,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彼棍,死亡現(xiàn)場離奇詭異,居然都是意外死亡膳算,警方通過查閱死者的電腦和手機(jī)座硕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涕蜂,“玉大人华匾,你說我怎么就攤上這事』叮” “怎么了蜘拉?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長有鹿。 經(jīng)常有香客問我旭旭,道長,這世上最難降的妖魔是什么葱跋? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任源梭,我火速辦了婚禮稍味,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脑溢。我一直安慰自己,他們只是感情好屑彻,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布社牲。 她就那樣靜靜地躺著悴了,像睡著了一般。 火紅的嫁衣襯著肌膚如雪湃交。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天息罗,我揣著相機(jī)與錄音迈喉,去河邊找鬼。 笑死挨摸,一個胖子當(dāng)著我的面吹牛岁歉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刨裆,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼帆啃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诽偷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤报慕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后飞苇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜗顽,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年忿等,在試婚紗的時候發(fā)現(xiàn)自己被綠了贸街。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡薛匪,死狀恐怖蛋辈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤渐白,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布纯衍,位于F島的核電站,受9級特大地震影響襟诸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜菇用,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一陷揪、第九天 我趴在偏房一處隱蔽的房頂上張望杂穷。 院中可真熱鬧卦绣,春花似錦、人聲如沸廊蜒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽樟凄。三九已至,卻和暖如春汰现,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞎饲。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工嗅战, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驮捍。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓脚曾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親珊泳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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