iOS runtime 的個人見解

runtime是一個iOS開發(fā)必須要了解的一個特別厲害的技術, 以前總是認為靠近底層的東西在實際中并不實用, 可是最近在項目中真真的用到...眼淚拌飯的感覺, 查找一個網(wǎng)上的資料做了個惡補, 同時也記錄一下吧.

首先說道官方的文字翻譯:iOS中的黑魔法, RunTime簡稱運行時, 運行時的機制是OC的一大特點, 簡單的說就是動態(tài)調用, 我們在編譯的階段并不能決定真正調用哪個函數(shù), 只有在運行的時候才能決定調用的函數(shù), 在C中, 在編譯的時候如果函數(shù)并沒有實現(xiàn), 我們是不能編譯通過的, 在OC中如果沒有實現(xiàn), 我們可以編譯通過(前提是我們聲明過), 但是在運行的過程中會崩潰,RunTime最重要的機制就是消息機制, 本質就是對象發(fā)送消息objc_msgSend

接下來我們創(chuàng)建一個工程, 命名隨便吧... 使用消息機制, 我們要先導入#import<objc/message.h>頭文件

我們可能會出現(xiàn) Too many arguments to function call, expected 0, have 3 之類的報錯

屏幕快照 2016-07-17 下午8.22.05.png

修改成如上 默認是YES我們該為NO, 報錯不存在了


消息收發(fā)機制


我們先看它的第一個功能吧, 就是消息收發(fā)機制
新建一個工具類, 名稱叫做ContactBook吧(聯(lián)系本, 原諒我考了四次沒考過的四級)
[ContactBook call]; //的本質就是下面這個在運行時轉變?yōu)橄旅孢@段代碼
objc_msgSend(ContactBook, @selector(call));
// 類方法
// 第一種通過類名調用
[ContactBook Dididi];
// 第二種通過類對象調用
[[ContactBook class] Dididi];
// 用類名調用, 底層會自動把類型轉變?yōu)轭悓ο笳{用
objc_msgSend([ContactBook class], @selector(Dididi));
ContactBook類中

@implementation ContactBook
- (void)eat { NSLog(@"吃人, 放血"); }
+ (void)Dididi { NSLog(@"上車小伙子, 開車啦"); }
@end
我們平時創(chuàng)建的對象alloc init那種在運行的時候會轉換成objc_msgsend這種形式; 或許有人會認為, 我們通過alloc init 能夠實現(xiàn)的, 為什么要這么麻煩. 下面要說的肯定就不會這么想的,


方法交換


 使用場景 :系統(tǒng)的API不能夠滿足我們的需求給系統(tǒng)擴充一些功能, 并保持原有的功能
 有兩種方案 第一種也是大家經(jīng)常用的一種, 繼承系統(tǒng)的類 重寫方法
 另外一種就是用RunTime交換方法

這個就是我們在項目中會用到的...
經(jīng)常會在項目中遇到展示圖片, 如果圖片是空我們要加一個站位的圖片
新建一個UIImage的Category
@implementation UIImage (Exchange)
//加載分類到內(nèi)存中調用這個api
+ (void)load { Method imageName = class_getClassMethod(self, @selector(imageNamed:)); Method imageWithName = class_getClassMethod(self, @selector(imageWithName:)); // 交換方法地址, 相當于交換實現(xiàn)方式 method_exchangeImplementations(imageName, imageWithName); }
+ (instancetype)imageWithName:(NSString *)name { // 這里調用imageWithName 相當于imageName UIImage *image = [self imageWithName:name]; if (image == nil) { [ UIImage *image = self imageWithName:@"占位圖片"] } return image; }


遍歷屬性


我們想要修改系統(tǒng)的私有屬性, 我們可以通過
unsigned int count = 0;//屬性個數(shù)!!! Ivar * ivars = class_copyIvarList( NSClassFromString(@"HKPerson"), &count); for(int i = 0 , i < count, i++) { Ivar ivar = ivars[i]; const char * name = ivar_getName(ivar); NSString * ocName = [NSString stringWithUTF8String:name]; NSLog(@"%@", ocName); }
我們可以找到想要修改的那個屬性名稱, 然后通過 KVC 給只讀屬性賦值...
這個我還用在歸檔跟反歸檔那個, 如果歸檔的屬性過多 我們還要一個一個的進行歸檔么?
利用這個完全不用

- (void)encodeWithCoder:(NSCoder *)coder { //歸檔 unsigned int count = 0;//屬性個數(shù)!!! Ivar * ivars = class_copyIvarList( [self class], &count); for (int i = 0; i < count; i ++) { Ivar ivar = ivars[i]; const char * name = ivar_getName(ivar); NSString * ocName = [NSString stringWithUTF8String:name]; [coder encodeObject:[self valueForKey:ocName] forKey:ocName]; } //在C語言里面一旦用到了 creat new copy 就需要釋放 free(ivars); }

- (instancetype)initWithCoder:(NSCoder *)coder { if (self = [super init]) { //解檔 unsigned int count = 0;//屬性個數(shù)!!! Ivar * ivars = class_copyIvarList( [self class], &count); for (int i = 0; i < count; i ++) { Ivar ivar = ivars[i]; const char * name = ivar_getName(ivar); NSString * ocName = [NSString stringWithUTF8String:name]; id value = [coder decodeObjectForKey:ocName]; [self setValue:value forKey:ocName]; } free(ivars); } return self; }
解決


動態(tài)添加方法


如果一個類方法非常多, 加載到內(nèi)存中的時候也比較耗費資源, 需要給每個方法生成映射表, 可以使用類動態(tài)的給某個類添加方法解決
新建一個Car類,
@implementation Car

void drive(id self, SEL sel){ NSLog(@"老司機帶帶我"); }
//當一個對象調用未實現(xiàn)的方法, 會調用這個處理并且會把對應的方法列表傳遞過來, 剛好我們可以用來判斷是不是我們想要動態(tài)添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{ if (sel == @selector(drive)) { // 動態(tài)添加drink方法 /* *參數(shù) *@param 參數(shù)1給哪個類添加方法 *@param 添加方法的方法編號 *@param 添加函數(shù)的地址(或者說是實現(xiàn)) *@param 函數(shù)地址的類型(返回值 + 參數(shù)類型) v代表void @代表對象 self :表示SEL->CMD */ class_addMethod(self, @selector(drive), drive, "v@:"); } return [super resolveInstanceMethod:sel]; }

@end
在控制器中這樣調用
[[[Car alloc] init] performSelector:@selector(drive)];
這樣就完成了在運行的時候添加一個方法


動態(tài)添加屬性


Extension跟Category大家都知道區(qū)別吧, 當我們需要在NSObject添加一個屬性, 并且每個子類都要有, 我們可以通過動態(tài)添加到NSObject中 Category(因為Extension中的子類并不能繼承, 不能完成需求)
新建一個NSObject的Category

static const char *key = "car"; @implementation NSObject (Property) *- (NSString *)car { // 關聯(lián)key return objc_getAssociatedObject(self, key); } *- (void)setCar:(NSString *)car { /* *@parma 參數(shù) *參數(shù)1 給那個對象添加關聯(lián) *參數(shù)2 關聯(lián)的key通過這個key獲取 *參數(shù)3 關聯(lián)的value *參數(shù)4 關聯(lián)的策略 */ objc_setAssociatedObject(self, key, car, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
然后在.h中寫上屬性名
@property (nonatomic, strong)NSString *car;
然后就可以在別的地方調用了
先到這里吧, 另外我還看到一些模型轉換的方法, 下次再整理一下吧...
各位加油, 向自己向往的境界前進

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奔浅,一起剝皮案震驚了整個濱河市仑性,隨后出現(xiàn)的幾起案子勿负,更是在濱河造成了極大的恐慌,老刑警劉巖他宛,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欠气,居然都是意外死亡厅各,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門预柒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來队塘,“玉大人,你說我怎么就攤上這事宜鸯°竟牛” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵淋袖,是天一觀的道長鸿市。 經(jīng)常有香客問我,道長适贸,這世上最難降的妖魔是什么灸芳? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮拜姿,結果婚禮上烙样,老公的妹妹穿的比我還像新娘。我一直安慰自己蕊肥,他們只是感情好谒获,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著壁却,像睡著了一般批狱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上展东,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天赔硫,我揣著相機與錄音,去河邊找鬼盐肃。 笑死爪膊,一個胖子當著我的面吹牛权悟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播推盛,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼峦阁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了耘成?” 一聲冷哼從身側響起榔昔,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瘪菌,沒想到半個月后撒会,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡控嗜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年茧彤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疆栏。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡曾掂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出壁顶,到底是詐尸還是另有隱情珠洗,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布若专,位于F島的核電站许蓖,受9級特大地震影響,放射性物質發(fā)生泄漏调衰。R本人自食惡果不足惜膊爪,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嚎莉。 院中可真熱鬧米酬,春花似錦、人聲如沸趋箩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叫确。三九已至跳芳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竹勉,已是汗流浹背飞盆。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桨啃。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓车胡,卻偏偏與公主長得像檬输,于是被迫代替她去往敵國和親照瘾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 我們常常會聽說 Objective-C 是一門動態(tài)語言丧慈,那么這個「動態(tài)」表現(xiàn)在哪呢析命?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,172評論 0 7
  • 轉至元數(shù)據(jù)結尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,679評論 0 9
  • 本文轉載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 748評論 0 1
  • 轉載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 727評論 0 2
  • 人的秘密―惹麻煩 真的逃默,作者猜中了我們的秘密鹃愤,怕惹麻煩是我們的死穴之一,我們常常不想惹麻煩而招來麻煩完域,帶來煩惱软吐。深...
    渴慕溪水邊閱讀 186評論 0 1