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

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

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

*定義

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

*進階

我們為什么要學習runtime
1.runtime可以遍歷類和對象的屬性、成員變量、方法、協議列表
2.runtime可以動態添加/修改屬性,動態添加/修改/替換方法,動態添加/修改/替換協議
3.runtime可以方法攔截調用

1.遍歷類和對象的屬性、成員變量、方法
通過使用runtime獲取類或對象的所有屬性、成員變量,包括我們在"command+左擊"進去看不到,然后通過

[object setValue:forKeyPath:@""];

進行屬性賦值。最常見的應該是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);
    }

*遍歷協議:
__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可以動態添加/修改屬性,動態添加/修改/替換方法,動態添加/修改/替換協議

*替換方法(攔截系統方法):
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 { 
}

*動態添加方法:(為什么動態添加方法)
使用場景:一個類方法非常多,一次性加載到內存比較耗費資源, OC都是懶加載,有些方法可能很久不會調用(只有滿足特定條件才會調用),所以就要動態添加方法。

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

// 當一個對象調用未實現的方法,會調用這個方法處理,并且會把對應的方法列表傳過來.
// 剛好可以用來判斷,未實現的方法是不是我們想要動態添加的方法
.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)) {
        // 動態添加eat方法
        // 第一個參數:給哪個類添加方法
        // 第二個參數:添加方法的方法編號
        // 第三個參數:添加方法的函數實現(函數地址)
        // 第四個參數:函數的類型,(返回值+參數類型) 
        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:保存到哪個對象中
     key:用什么屬性保存 屬性名
     value:保存值
     policy:策略,strong,weak
     */
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name
{
    return objc_getAssociatedObject(self, "name");
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

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