貓貓學(xué)iOS之RunTime動(dòng)態(tài)添加方法屬性

貓貓分享,必須精品

原創(chuàng)文章质欲,歡迎轉(zhuǎn)載糠馆。轉(zhuǎn)載請(qǐng)注明:翟乃玉的博客
地址:http://www.reibang.com/notebooks/4236923/latest

一:runtime動(dòng)態(tài)添加方法

應(yīng)用場(chǎng)景:

面試中有人會(huì)這么問(wèn):你有用過(guò) performSelector 方法嗎又碌?

貓貓傻傻的說(shuō),用過(guò)呀耽装,這個(gè)還是很好用的期揪,比如我可以延遲幾秒鐘運(yùn)行這個(gè)方法,或者是選擇在哪個(gè)線程中運(yùn)行姓建,不用寫GCD那一大串的代碼速兔,顯得代碼簡(jiǎn)潔明了活玲。谍婉。穗熬。(得意中丁溅,從一般扯到了GCD,快來(lái)夸夸我窟赏,多膩害Q那睢)
好吧,其實(shí)人家是想問(wèn)有沒有用到過(guò)動(dòng)態(tài)添加方法作煌,但是我的一串說(shuō)辭完全給自己封路了蝠嘉,其實(shí)之前對(duì)于runtime有過(guò)了解蚤告,現(xiàn)在呢就仔細(xì)說(shuō)說(shuō)吧:

  • performSelector方法區(qū)別于直接調(diào)用,如果我調(diào)用一個(gè)沒有定義的方法获诈,在編譯時(shí)直接調(diào)用會(huì)給報(bào)錯(cuò)心褐,紅色的哦逗爹。如果用的是performSelector方法,那就只會(huì)有警告(貌似早期木有)挟冠。所以袍睡,人家想問(wèn)得就是,你有沒有用過(guò)動(dòng)態(tài)添加方法控淡,貓給翻譯下就是掺炭,一個(gè)方法我沒有定義,直接調(diào)找不到泥栖,但是我還想運(yùn)行他勋篓,你能辦到嗎譬嚣?(喵你一臉钞它。页响。搀庶。)如下圖


    直接調(diào)用和performSelector區(qū)別
  • 我想大家應(yīng)該明白了,其實(shí)這東西跟懶加載差不多小腊,這問(wèn)題也不是說(shuō)面試人吃飽了撐得沒事干弄出來(lái)的久窟,他是有真實(shí)意義存在的(雖然我就認(rèn)為他吃飽撐的)斥扛。當(dāng)硬件內(nèi)存過(guò)小的時(shí)候,如果我們將每個(gè)方法都直接加到內(nèi)存當(dāng)中去芬失,但是幾百年不用一次峻村,這樣就造成了浪費(fèi)粘昨,就跟懶加載一樣窜锯,我方法定義好锚扎,但是只有當(dāng)你用的時(shí)候我猜加載你馁启,這個(gè)呢就必須用到runtime的一些知識(shí)了惯疙。就是performSelector:以及動(dòng)態(tài)添加方法

解決

首先定義一個(gè)類Cat,然后我們假設(shè)貓有個(gè)eat的方法对碌,用performSelector調(diào)用蒿偎。

@interface Cat : NSObject
@end
@implementation Cat
@end

然后如下調(diào)用

調(diào)用

就崩了诉位。苍糠。。:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Cat eat:]: unrecognized selector sent to instance 0x7ff1baf08160'

不蹦才怪歹袁,啥都沒有的的空定義類条舔,就繼承了NSObject乏矾,連瞎貓都不算钻心。

  • 正經(jīng)的代碼中,當(dāng)performSelector方法調(diào)用某個(gè)sel的時(shí)候摊沉,這時(shí)候會(huì)到調(diào)用對(duì)象的+ (BOOL)resolveInstanceMethod:(SEL)sel方法中说墨,如果這里返回是NO,就表示找不到
void eat(id self, SEL _cmd, NSString *param){
   NSLog(@"調(diào)用eat 參數(shù):1%@ 參數(shù)2:%@ 參數(shù)3:%@",self,NSStringFromSelector(_cmd),param);
}
@interface Cat : NSObject

@end

@implementation Cat

+(BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(eat:)) {
        
        /**
         *  動(dòng)態(tài)添加方法
         *
         *  @param self cls:為哪個(gè)類添加方法
         *  @param sel  SEL:添加方法的方法編號(hào)(方法名)是什么
         *  @param IMP  IMP:方法實(shí)現(xiàn)
         *  @param const char * types方法類型
         *
         *  @return 返回是否添加成功
         */
        BOOL isSuccess = class_addMethod(self, sel, (IMP)eat, "v@:@");
        
        return isSuccess;
        
    }
    
    return [super resolveInstanceMethod:sel];
}
@end

  • 用上面的代碼聲明,然后調(diào)用


    調(diào)用成功

這時(shí)候就是調(diào)用成功了楼咳。

補(bǔ)充

一: 動(dòng)態(tài)添加方法烛恤,首要要實(shí)現(xiàn)要添加類的resolveInstanceMethod方法。

  • resolveInstanceMethod的作用就是當(dāng)調(diào)用了沒有實(shí)現(xiàn)的方法沒有實(shí)現(xiàn)就會(huì)調(diào)用糙申,然后就可以根據(jù)他的參數(shù)sel(參數(shù)sel就是沒有實(shí)現(xiàn)的方法)來(lái)做一系列的操作。
  • 此方法定義于NSObject當(dāng)中粱锐,所以說(shuō)每個(gè)類其實(shí)都有他扛邑,只要重寫蔬崩,不過(guò)不要忘了方法后面的return [super resolveInstanceMethod:sel];。其實(shí)這些可以看官方文檔的跨琳,雖然貓的英語(yǔ)很爛脉让,但是在有道詞典的幫助下還是能看懂的功炮,我相信你也可以溅潜。
  /**
   *  當(dāng)調(diào)用了沒有實(shí)現(xiàn)的方法沒有實(shí)現(xiàn)就會(huì)調(diào)用
   *
   *  @param sel 沒有實(shí)現(xiàn)方法
   *
   *  @return 如果方法被發(fā)現(xiàn)并添加return:Yes 否則NO
   */
  + (BOOL)resolveInstanceMethod:(SEL)sel;

二: 對(duì)于自己提前定義的方法eat:來(lái)說(shuō),很明顯這是c語(yǔ)音定義的方法薪伏,與平常方法不同的是他多了兩個(gè)參數(shù)滚澜,其實(shí)OC當(dāng)中每個(gè)方法里面都有這兩個(gè)參數(shù),他們是隱藏參數(shù)嫁怀,一個(gè)代表本身设捐,另一個(gè)代碼的是方法名SEL潦牛,通過(guò)圖調(diào)用成功 那里你可以看到打印的結(jié)果。

/**
 *  吃方法
 *
 *  @param self  隱藏參數(shù) self
 *  @param _cmd  隱藏參數(shù) SEL
 *  @param param 參數(shù)
 */
void eat(id self, SEL _cmd, NSString *param){
   NSLog(@"調(diào)用eat 參數(shù):1%@ 參數(shù)2:%@ 參數(shù)3:%@",self,NSStringFromSelector(_cmd),param);
}

三:動(dòng)態(tài)添加時(shí)用的的方法

/**
         *  動(dòng)態(tài)添加方法
         *
         *  @param self cls:為哪個(gè)類添加方法
         *  @param sel  SEL:添加方法的方法編號(hào)(方法名)是什么
         *  @param IMP  IMP:方法實(shí)現(xiàn)
         *  @param const char * types方法類型
         *
         *  @return 返回是否添加成功
         */
        BOOL isSuccess = class_addMethod(self, sel, (IMP)eat, "v@:@");
  • 這里的基本東西前文說(shuō)的挺多了挡育,唯一就是最后一個(gè)參數(shù) @param const char * types方法類型這個(gè)是沒有見過(guò)的,其是可以通過(guò)查閱官方文檔了解的即寒。
    types表

查找方法:看圖按照步驟1橡淆,2,3(貓貓最開始找的時(shí)候就是瞎找母赵,看到像的就點(diǎn)點(diǎn)逸爵,英語(yǔ)是硬傷啊,看代碼還行凹嘲,看英文注釋感覺貓貓要瞎笆蟆)

官方手冊(cè)查找

二:runtime動(dòng)態(tài)添加屬性

應(yīng)用場(chǎng)景

在分類中,所寫的@property (nonatomic, strong) NSString *name;都僅僅是生成了get和set方法周蹭,并沒有生成對(duì)應(yīng)的_name屬性趋艘,但是有時(shí)候我們會(huì)有一種需求,想要讓分類中保存一下新的屬性值凶朗,因?yàn)閟et和get方法只能是對(duì)已經(jīng)有的東西做操作瓷胧,比如說(shuō)最常用的UIView的分類我們對(duì)frame中的x,y棚愤,width搓萧,height做操作。

解決

用runtime動(dòng)態(tài)的給分類添加屬性宛畦,并且另他產(chǎn)生關(guān)聯(lián)瘸洛,使用如下

  • 聲明:
@interface NSObject (Objc)

@property (nonatomic, strong) NSString *name;

@end
  • 實(shí)現(xiàn)getSet方法

#import "NSObject+Objc.h"

#import <objc/message.h>

@implementation NSObject (Objc)

- (void)setName:(NSString *)name{
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name{
    return objc_getAssociatedObject(self, @"name");
    
}

@end
  • 運(yùn)行
#import "ViewController.h"

#import "NSObject+Objc.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSObject *objc = [[NSObject alloc] init];
    objc.name = @"貓貓";
    NSLog(@"%@",objc.name);
}
@end
打印結(jié)果

補(bǔ)充解釋

  • runtime中的objc_setAssociatedObject方法
    /**
     *  根據(jù)某個(gè)對(duì)象,還有key次和,還有對(duì)應(yīng)的策略(copy,strong等) 動(dòng)態(tài)的將值設(shè)置到這個(gè)對(duì)象的key上
     *
     *  @param object 某個(gè)對(duì)象
     *  @param key    屬性名,根據(jù)key去獲取關(guān)聯(lián)的對(duì)象
     *  @param value  要設(shè)置的值
     *  @param policy 策略(copy,strong反肋,assign等)
     */
    OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
  • runtime中的objc_getAssociatedObject方法
    /**
     *  根據(jù)某個(gè)對(duì)象,還有key 動(dòng)態(tài)的獲取到這個(gè)對(duì)象的key對(duì)應(yīng)的屬性的值
     *
     *  @param object 某個(gè)對(duì)象
     *  @param key    key
     *
     *  @return 對(duì)象的值
     */
    OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末斯够,一起剝皮案震驚了整個(gè)濱河市囚玫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌读规,老刑警劉巖抓督,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異束亏,居然都是意外死亡铃在,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)定铜,“玉大人阳液,你說(shuō)我怎么就攤上這事〈Э唬” “怎么了帘皿?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)畸陡。 經(jīng)常有香客問(wèn)我鹰溜,道長(zhǎng),這世上最難降的妖魔是什么丁恭? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任曹动,我火速辦了婚禮,結(jié)果婚禮上牲览,老公的妹妹穿的比我還像新娘墓陈。我一直安慰自己,他們只是感情好第献,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布贡必。 她就那樣靜靜地躺著,像睡著了一般痊硕。 火紅的嫁衣襯著肌膚如雪赊级。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天岔绸,我揣著相機(jī)與錄音,去河邊找鬼橡伞。 笑死盒揉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兑徘。 我是一名探鬼主播刚盈,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼挂脑!你這毒婦竟也來(lái)了藕漱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤崭闲,失蹤者是張志新(化名)和其女友劉穎肋联,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刁俭,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橄仍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侮繁。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虑粥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宪哩,到底是詐尸還是另有隱情娩贷,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布锁孟,位于F島的核電站育勺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏罗岖。R本人自食惡果不足惜涧至,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桑包。 院中可真熱鬧南蓬,春花似錦、人聲如沸哑了。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弱左。三九已至窄陡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拆火,已是汗流浹背跳夭。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留们镜,地道東北人币叹。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像模狭,于是被迫代替她去往敵國(guó)和親颈抚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉嚼鹉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,679評(píng)論 0 9
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 748評(píng)論 0 1
  • 我們常常會(huì)聽說(shuō) Objective-C 是一門動(dòng)態(tài)語(yǔ)言贩汉,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,174評(píng)論 0 7
  • 對(duì)于從事 iOS 開發(fā)人員來(lái)說(shuō)锚赤,所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 3,697評(píng)論 7 64
  • 昨天參加了@學(xué)霸貓 BVM4.0 (best version of me) 的第一次課宴树,收獲有很多策菜,我會(huì)分幾篇文章...
    李智閱讀 714評(píng)論 0 5