iOS runtime介紹、使用(基本方法篇)

*看完本篇之后你將獲得:

1.了解什么是runtime
2.知道可以利用runtime做到哪些事情
3.掌握用runtime開發(fā)的常用方法

*定義

1.RunTime簡稱運(yùn)行時(shí),就是系統(tǒng)在運(yùn)行的時(shí)候的一些機(jī)制,其中最主要的是消息機(jī)制。
2.對于C語言,函數(shù)的調(diào)用在編譯的時(shí)候會決定調(diào)用哪個(gè)函數(shù),編譯完成之后直接順序執(zhí)行,無任何二義性。
3.OC的函數(shù)調(diào)用成為消息發(fā)送。屬于動(dòng)態(tài)調(diào)用過程。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)(事實(shí)證明,在編 譯階段,OC可以調(diào)用任何函數(shù),即使這個(gè)函數(shù)并未實(shí)現(xiàn),只要申明過就不會報(bào)錯(cuò)。而C語言在編譯階段就會報(bào)錯(cuò))。
4.只有在真正運(yùn)行的時(shí)候才會根據(jù)函數(shù)的名稱找 到對應(yīng)的函數(shù)來調(diào)用。

*進(jìn)階

我們?yōu)槭裁匆獙W(xué)習(xí)runtime
1.runtime可以遍歷類和對象的屬性、成員變量、方法、協(xié)議列表
2.runtime可以動(dòng)態(tài)添加/修改屬性,動(dòng)態(tài)添加/修改/替換方法,動(dòng)態(tài)添加/修改/替換協(xié)議
3.runtime可以方法攔截調(diào)用

1.遍歷類和對象的屬性、成員變量、方法
通過使用runtime獲取類或?qū)ο蟮乃袑傩?、成員變量,包括我們在"command+左擊"進(jìn)去看不到,然后通過

[object setValue:forKeyPath:@""];

進(jìn)行屬性賦值。最常見的應(yīng)該是TextField的placeholder字體顏色了:

[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];

具體代碼如下:

*遍歷屬性:
    unsigned int count;
    objc_property_t *properties = class_copyPropertyList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        const char *propertiesName = property_getName(properties[i]);
        NSString *str = [NSString stringWithCString:propertiesName encoding:NSUTF8StringEncoding];
        NSLog(@"propertyName : %@", str);
    }

*遍歷成員變量:
    typedef struct objc_ivar *Ivar;
    unsigned int count;
    Ivar *ivars = class_copyIvarList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        const char *ivarName = ivar_getName(ivars[i]);
        NSString *str = [NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding];
        NSLog(@"ivarName : %@", str);
    }

*遍歷方法:
unsigned count = 0;
    // 獲取所有方法
    Method *methods = class_copyMethodList([UIView class], &count);
    for (int i = 0; i < count; i++) {
        Method method = methods[i];
        // 方法類型是SEL選擇器類型
        SEL methodName = method_getName(method);
        NSString *str = [NSString stringWithCString:sel_getName(methodName) encoding:NSUTF8StringEncoding];
        
        int arguments = method_getNumberOfArguments(method);
        NSLog(@"methodName : %@, arguments Count: %d", str, arguments);
    }

*遍歷協(xié)議:
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
    for (unsigned int i; i<count; i++) {
        Protocol *myProtocal = protocolList[i];
        const char *protocolName = protocol_getName(myProtocal);
        NSLog(@"protocol---->%@", [NSString stringWithUTF8String:protocolName]);
    }

2.runtime可以動(dòng)態(tài)添加/修改屬性,動(dòng)態(tài)添加/修改/替換方法,動(dòng)態(tài)添加/修改/替換協(xié)議

*替換方法(攔截系統(tǒng)方法):
Method origin = class_getInstanceMethod([UIView class], @selector(touchesBegan:withEvent:)); 
Method custom = class_getInstanceMethod([UIView class], @selector(custom_touchesBegan:withEvent:)); 
method_exchangeImplementations(origin, custom);

- (void)custom_touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 
}

*動(dòng)態(tài)添加方法:(為什么動(dòng)態(tài)添加方法)
使用場景:一個(gè)類方法非常多,一次性加載到內(nèi)存比較耗費(fèi)資源, OC都是懶加載,有些方法可能很久不會調(diào)用(只有滿足特定條件才會調(diào)用),所以就要?jiǎng)討B(tài)添加方法。

調(diào)用eat方法
    Person *p = [[Person alloc] init];
    [p performSelector:@selector(eat)];

// 當(dāng)一個(gè)對象調(diào)用未實(shí)現(xiàn)的方法,會調(diào)用這個(gè)方法處理,并且會把對應(yīng)的方法列表傳過來.
// 剛好可以用來判斷,未實(shí)現(xiàn)的方法是不是我們想要?jiǎng)討B(tài)添加的方法
.m
#import "Person.h"
@implementation Person

void eat(id self,SEL sel){
    NSLog(@"---runtime---%@ %@",self,NSStringFromSelector(sel));
}

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(eat)) {
        // 動(dòng)態(tài)添加eat方法
        // 第一個(gè)參數(shù):給哪個(gè)類添加方法
        // 第二個(gè)參數(shù):添加方法的方法編號
        // 第三個(gè)參數(shù):添加方法的函數(shù)實(shí)現(xiàn)(函數(shù)地址)
        // 第四個(gè)參數(shù):函數(shù)的類型,(返回值+參數(shù)類型) 
        class_addMethod(self, @selector(eat), (IMP)eat, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
@end



*給category添加屬性:

.h
#import <Foundation/Foundation.h>
@interface NSObject (Property){
}
@property (nonatomic,copy) NSString *name;
@end

.m
#import "NSObject+Property.h"
@implementation NSObject (Property)

- (void)setName:(NSString *)name
{
    /*
     object:保存到哪個(gè)對象中
     key:用什么屬性保存 屬性名
     value:保存值
     policy:策略,strong,weak
     */
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name
{
    return objc_getAssociatedObject(self, "name");
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,804評論 7 64
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,881評論 33 466
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,041評論 0 9
  • 剛剛觀摩阿黎的分享,深受啟發(fā),不僅為小米模式叫好,更為一個(gè)品牌任性成長軌跡而拍手叫絕。 夜已近深了,我把總結(jié)歸納一...
    喬杜先生閱讀 276評論 0 0
  • 對于富媒體的文本,使用TTTAttributedLabel是一個(gè)不錯(cuò)的選擇。代碼中有很多和我們自己業(yè)務(wù)相關(guān)的部分,...
    小曼blog閱讀 2,032評論 0 2

友情鏈接更多精彩內(nèi)容