運行時相關(guān)

  • 在CYPerson.h文件中
#import <Foundation/Foundation.h>


@interface CYPerson : NSObject
{
    int _money;
}
@property (nonatomic, assign, readonly) int age;
@property (nonatomic, assign) double height;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSArray *books;
@property (nonatomic, strong) id test;
@property (nonatomic, assign) CGRect rect;
@property (nonatomic, copy) void (^block)();
@property (nonatomic, assign) int *p;
@property (nonatomic, strong) CYCat *cat;
@end
  • 在CYPerson.m中
#import "CYPerson.h"

@implementation CYPerson

@end
  • 在main.m文件中
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "CYPerson.h"

void getIvars()
{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([CYPerson class], &count);
    // class_copyIvarList獲取成員變量列表,它返回的是一個指針指向的是最前面的那一個
    // ([CYPerson class], &count)這里面放的是類狡忙,你把類給我庶骄,我就獲取里面所有的成員變量。&count放的是成員變量的個數(shù)
    for (int i = 0; i < count; i++) {
        // for循環(huán)把所有成員變量遍歷出來
        Ivar ivar = ivars[i]; // *(ivars + i)
        // 取出每一個成員變量Ivar胡嘿,而且Ivar是以數(shù)組的形式去訪問
        // ivars[i]的寫法相當(dāng)于*(ivars + i)---跳到下一個疏魏,取出這個指針指向的東西
        NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
       // %s是因為這里是C語言的東西
       // ivar_getName(ivar)這是去獲取所有成員變量的名字停做,這樣就挖掘到了所有成員變量
       // ivar_getTypeEncoding(ivar)表示獲取一個成員變量的類型字符串
       // 而且今后如果你有要獲取所有什么double,int類型的成員變量大莫,這種方式蛉腌,一打印就出來了
    }

    free(ivars);
    // 這里是通過copy出來的,所以需要釋放的
}

// 這里獲取所有屬性只厘,和上面一樣
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        unsigned int count = 0;
        objc_property_t *properties = class_copyPropertyList([CYPerson class], &count);
        // class_copyPropertyList獲取屬性列表
        // class_copyProtocolList([CYPerson class], &count);是獲取協(xié)議列表烙丛,這樣可以獲取這個類遵循的所有協(xié)議
        // class_copyMethodList([CYPerson class], &count);是獲取方法列表,這樣可以知道這個類遵循 那些方法
        for (int i = 0; i < count; i++) {
            objc_property_t property = properties[i];
            NSLog(@"%s   ----     %s", property_getName(property), property_getAttributes(property));
       // property_getName(property)這是去獲取所有屬性的名字
       // property_getAttributes(property)獲取所有屬性的類型
        }

        free(properties);

//        method_exchangeImplementations(<#Method m1#>, <#Method m2#>)
//        方法交換---這個方法的意義在于我可以將蘋果系統(tǒng)內(nèi)部的方法替換成我自己的方法懈凹。當(dāng)你認(rèn)為系統(tǒng)自帶的方法不好用時蜀变,你就將它替換為自己的方法
    }
    return 0;
}

*


*

*


*

*


*

  • 運行時還可以動態(tài)添加成員變量方法,動態(tài)添加方法介评,動態(tài)添加屬性库北,動態(tài)添加協(xié)議這四個方法
  • 假如說在代碼里面你只寫了如上幾個屬性,但是在我動態(tài)添加后们陆,在程序運行過程中會無緣無故多一個屬性出來寒瓦,但是你在代碼中是看不見的。這就是運行時能干的事情坪仇,相當(dāng)于操縱你的內(nèi)存杂腰,但是這也僅僅是運行時的冰山一角

*


*

        method_exchangeImplementations(<#Method m1#>, <#Method m2#>)
//      方法交換---這個方法的意義在于我可以將蘋果系統(tǒng)內(nèi)部的方法替換成我自己的方法。當(dāng)你認(rèn)為系統(tǒng)自帶的方法不好用時椅文,你就將它替換為自己的方法





  • RunTime
    • 1.獲取內(nèi)部所有屬性和成員變量
    • 2.Method Swizzle--iOS黑魔法
      • 直觀用途:交換方法實現(xiàn)
  • 在CYPerson.h文件中
#import <Foundation/Foundation.h>

@interface CYPerson : NSObject
- (void)run;
- (void)study;
@end
  • 在CYPerson.m文件中
#import "CYPerson.h"
@implementation CYPerson

- (void)run
{
    NSLog(@"%s", __func__);
}

- (void)study
{
    NSLog(@"%s", __func__);
}

@end
#import "ViewController.h"
#import "CYPerson.h"
#import <objc/runtime.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

        Method method1 = class_getInstanceMethod([CYPerson class], @selector(run));
        Method method2 = class_getInstanceMethod([CYPerson class], @selector(study));
        method_exchangeImplementations(method1, method2);


        CYPerson *p = [[CYPerson alloc] init];
        [p run];

        [p study];
  • 可以看出來:我調(diào)用run喂很,它執(zhí)行的study。我調(diào)用study皆刺,它執(zhí)行的run

  • 那這個有啥用呢少辣?
    • 在這里看出來是沒什么卵用,但是它的價值就在于可以交換系統(tǒng)自帶的方法
    • 比如說我可以讓控制器的viewDidLoad方法換成我自己的viewDidLoad方法羡蛾,讓它執(zhí)行的時候執(zhí)行到我自己的方法中去了漓帅。
    • 下面舉個例子:
      • 我想監(jiān)控控制器什么時候死亡,那我就得重寫dealloc方法。那么假如我們的項目中有30個或者更多的控制器忙干,我想看它死掉沒有器予,防止循環(huán)引用,那我是不是20個都得實現(xiàn)dealloc方法捐迫?那我何不再搞一個方法出來乾翔,比如說CY_dealloc:方法。你本來想執(zhí)行dealloc的弓乙,現(xiàn)在執(zhí)行到我CY_dealloc:方法里去末融。那我就可以在這里統(tǒng)一監(jiān)控所有控制器的死亡
      • 下面我就做一下這個事情。為了保證所有控制器都有暇韧,我弄一個控制器的分類--UIViewController+CYExtention
#import <UIKit/UIKit.h>
#import <objc/runtime.h>

@implementation UIViewController (CYExtension)
+ (void)load
{
    Method method1 = class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));
    Method method2 = class_getInstanceMethod(self, @selector(CY_dealloc));
    method_exchangeImplementations(method1, method2);
}

- (void)CY_dealloc
{
    NSLog(@"%@ - CY_dealloc", self);
}
@end
  • 這樣就讓所有控制器的dealloc來到了我CY_dealloc里面,我可以統(tǒng)一監(jiān)控所有控制器
    • 上面我沒有導(dǎo)入頭文件浓瞪,是因為load方法是只要載入到內(nèi)存就會調(diào)一次懈玻,這個分類文件肯定是要裝入內(nèi)存的,所以頭文件要不要都無所謂乾颁,沒什么價值涂乌。但是你的導(dǎo)入#import <UIKit/UIKit.h>。因為我得拿控制器的名字
  • 我在Main.storyboard中弄多一些控制器會發(fā)現(xiàn):
  • 這樣的話英岭,任何一個控制器掛了我都能監(jiān)控得到

  • 這里有一個小問題:
    • 我在viewController.m文件中加上dealloc
- (void)dealloc
{
    NSLog(@"-------dealloc");
}
  • 然后讓上圖中的第二個控制器class為我們的viewController湾盒,運行打印,會發(fā)現(xiàn)
  • 按理來說诅妹,一運行點擊button后點擊返回是應(yīng)該調(diào)用dealloc方法罚勾,但是一調(diào)用它是應(yīng)該來到我們的CY_dealloc方法,應(yīng)該是只打印出CY_dealloc的吭狡,但是打印出來還是調(diào)用了dealloc方法尖殃。這是為什么呢?
    • 你會發(fā)現(xiàn)划煮,我們開始寫Method method1 = class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));的時候送丰,開始如果寫的是@selector(@"dealloc"),這是禁止的弛秋,說明這個方法ARC情況下是比較特殊的器躏。但是前面@selector(run)和@selector(study)它們交換方法后,只打印了對方的方法蟹略,自己的方法就不會調(diào)用了登失。
    • 但是這里這么弄也正是我要說的效果:用我們的方法交換系統(tǒng)的方法后還是想辦到系統(tǒng)的方法還是能調(diào)。因為我們有時候是想在控制器死掉的時候做一些事情科乎。比如說:在控制器死掉的時候清?掉一些東西壁畸,或者在控制器死掉的時候做一些請求:取消通知
- (void)dealloc
{
    NSLog(@"-------dealloc");

        self.data = nil;
        self.images = nil;

        [self cancel];
}
  • 但是如果按照開始的做法,我把dealloc換成CY_dealloc,就意味著我以后調(diào)dealloc只會來到CY_dealloc捏萍,以前系統(tǒng)的dealloc就沒法執(zhí)行太抓。但是這里上面系統(tǒng)的dealloc可以執(zhí)行,但我告訴你如果換成了普通的方法它是不可能執(zhí)行的令杈。就行前面我執(zhí)行run的時候它不可能執(zhí)行study走敌,這兩個方法只會執(zhí)行它對應(yīng)的方法
  • 所以今后你如果做了方法的調(diào)換,不是系統(tǒng)的逗噩,我說的是普通的方法換了掉丽。你如果調(diào)換后還想調(diào)回以前的方法,那就做一件事情執(zhí)行以下:(self.對應(yīng)的方法)异雁。只有這樣它才會又調(diào)回自己以前的方法捶障。因為你這樣僅僅是做一個攔截嘛!就像下面:
- (void)CY_dealloc
{
    NSLog(@"%@ - CY_dealloc", self);

        [self CY_dealloc];
        //  這樣調(diào)用的是dealloc纲刀,又調(diào)回去了
}
  • 這里的意思:當(dāng)一個控制器死掉的時候项炼,它肯定會調(diào)dealloc,但dealloc方法實現(xiàn)被我換掉了示绊。所以它來到了CY_dealloc锭部。執(zhí)行完- (void)CY_dealloc
    {
    NSLog(@"%@ - CY_dealloc", self);這段代碼,我再調(diào)用[self CY_dealloc];面褐,它的方法實現(xiàn)是dealloc拌禾,所以又調(diào)回去了。所以今后你把系統(tǒng)方法換掉以后展哭,我建議你再調(diào)回去湃窍,當(dāng)然有些特殊情況就特殊處理。
  • 那這個有什么價值呢摄杂?
    • 第一個以及體現(xiàn)了價值:攔截系統(tǒng)方法調(diào)用坝咐,我就可以在系統(tǒng)方法調(diào)用之前或者調(diào)用之后做一些事情
    • 第二個價值舉個例子:
      • 使用字典和數(shù)組的時候一直有一個頭疼的問題:字典和數(shù)組賦值的時候不能為空,否則報錯: object cannot be nil'
    NSString *value = nil;

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //    dict[@"name"] = value;

    NSMutableArray *array = [NSMutableArray array];
    [array addObject:value];
    array[0] = value;
  • 但是我們很多時候不知道別人給你傳的值是不是空拔龌帧墨坚!為了不報錯,我們經(jīng)常都得進(jìn)行判斷:如果value有值映挂,我再執(zhí)行泽篮。
  • 那有沒有一個辦法可以過濾掉這些東西呢?只要發(fā)現(xiàn)傳進(jìn)來的值是個空的柑船,我就不處理帽撑,那可不可以一勞永逸做到這點呢?我們只要寫下某一段代碼鞍时,以后凡是項目中傳空的值進(jìn)來亏拉,它都不報錯了扣蜻,怎么去做呢?
    • 只要將NSMutable--的addObject:方法換掉及塘,攔截這個方法莽使,鴨蛋發(fā)現(xiàn)傳進(jìn)來的值是空的我就不調(diào),如果傳進(jìn)來的值不是nil笙僚,我就調(diào)回它以前的方法芳肌。那么這樣的話今后數(shù)組的訪問或者字典的訪問就不會存在傳進(jìn)來值為空報錯的問題了
  • 還舉個例子:[UIImage imageName:我完全可以將imageName:方法攔截一下,我就可以對它傳進(jìn)來的圖片名進(jìn)行統(tǒng)一處理肋层,比如說什么夜間模式亿笤,什么皮膚,我就可以根據(jù)文件名去加載另外一個文件栋猖,統(tǒng)一攔截所有圖片

  • 但是還是不能亂換亂用净薛,只是有些特殊功能可以做一下,亂用的話就不好了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掂铐,一起剝皮案震驚了整個濱河市罕拂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌全陨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衷掷,死亡現(xiàn)場離奇詭異辱姨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)戚嗅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門雨涛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人懦胞,你說我怎么就攤上這事替久。” “怎么了躏尉?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵蚯根,是天一觀的道長。 經(jīng)常有香客問我胀糜,道長颅拦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任教藻,我火速辦了婚禮距帅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘括堤。我一直安慰自己碌秸,他們只是感情好绍移,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讥电,像睡著了一般蹂窖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上允趟,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天恼策,我揣著相機(jī)與錄音,去河邊找鬼潮剪。 笑死涣楷,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抗碰。 我是一名探鬼主播狮斗,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼弧蝇!你這毒婦竟也來了碳褒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤看疗,失蹤者是張志新(化名)和其女友劉穎沙峻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體两芳,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡摔寨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了怖辆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片是复。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖竖螃,靈堂內(nèi)的尸體忽然破棺而出淑廊,到底是詐尸還是另有隱情,我是刑警寧澤特咆,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布季惩,位于F島的核電站,受9級特大地震影響坚弱,放射性物質(zhì)發(fā)生泄漏蜀备。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一荒叶、第九天 我趴在偏房一處隱蔽的房頂上張望碾阁。 院中可真熱鬧,春花似錦些楣、人聲如沸脂凶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚕钦。三九已至亭病,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘶居,已是汗流浹背罪帖。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留邮屁,地道東北人整袁。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像佑吝,于是被迫代替她去往敵國和親坐昙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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