1. 程式人生 > >runtime 執行時機制

runtime 執行時機制

runtime是一套比較底層的純C語言API, 屬於1個C語言庫, 包含了很多底層的C語言API。 在我們平時編寫的OC程式碼中, 程式執行過程時, 其實最終都是轉成了runtime的C語言程式碼, runtime算是OC的幕後工作者 比如說,下面一個建立物件的方法中, 舉例: OC : [[MJPerson alloc] init] runtime : objc_msgSend(objc_msgSend("MJPerson" , "alloc"), "init")

runtime是屬於OC的底層, 可以進行一些非常底層的操作(用OC是無法現實的, 不好實現)

  • 在程式執行過程中, 動態建立一個類(比如KVO的底層實現)
  • 在程式執行過程中, 動態地為某個類新增屬性\方法, 修改屬性值\方法
  • 遍歷一個類的所有成員變數(屬性)\所有方法 例如:我們需要對一個類的屬性進行歸檔解檔的時候屬性特別的多,這時候,我們就會寫很多對應的程式碼,但是如果使用了runtime就可以動態設定! 例如程式碼舉例 一、

2> 相關應用

  • NSCoding(歸檔和解檔, 利用runtime遍歷模型物件的所有屬性)
  • 字典 --> 模型 (利用runtime遍歷模型物件的所有屬性, 根據屬性名從字典中取出對應的值, 設定到模型的屬性上)
  • KVO(利用runtime動態產生一個類)
  • 用於封裝框架(想怎麼改就怎麼改) 這就是我們runtime機制的只要運用方向

3> 相關函式

  • objc_msgSend : 給物件傳送訊息
  • class_copyMethodList : 遍歷某個類所有的方法
  • class_copyIvarList : 遍歷某個類所有的成員變數
  • class_..... 這是我們學習runtime必須知道的函式


#import <objc/runtime.h>
#import <objc/message.h>

 舉例一、獲取一個類的成員變數  ivar_getName

@class Person;
-(void)encodeWithCoder:(NSCoder )encoder
{
    unsigned int count = 0;
    Ivar ivars = class_copyIvarList([Person class], &count);
    
    for (int i = 0; i<count; i++) {
        
        // 取出i位置對應的成員變數
        Ivar ivar = ivars[i];
        
        // 檢視成員變數
        const char *name = ivar_getName(ivar);
        
        // 歸檔
        NSString *key = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:key];
        [encoder encodeObject:value forKey:key];
    }
    
    free(ivars);
}

-(id)initWithCoder:(NSCoder *)decoder
{
    if (self = [super init])
    {
        
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([Person class], &count);
        
        for (int i = 0; i<count; i++) {
            // 取出i位置對應的成員變數
            Ivar ivar = ivars[i];
            
            // 檢視成員變數
            const char *name = ivar_getName(ivar);
            
            // 歸檔
            NSString *key = [NSString stringWithUTF8String:name];
            id value = [decoder decodeObjectForKey:key];
            
            // 設定到成員變數身上
            [self setValue:value forKey:key];
        }
        
        free(ivars);
    }
    return self;
}


舉例二、拓展成員變數(get 、set 方法)

@interface LolaTrackInfo (AddressParse)

@property (nonatomic) BOOL everParsedAddress;

@end

@implementation LolaTrackInfo (AddressParse)

static char parseAdKey;

-(BOOL)everParsedAddress
{
    NSNumber *b = objc_getAssociatedObject(self, &parseAdKey);
    return b.boolValue;
}

-(void)setEverParsedAddress:(BOOL)everParsedAddress
{
    objc_setAssociatedObject(self, &parseAdKey, [NSNumber numberWithBool:everParsedAddress], OBJC_ASSOCIATION_RETAIN);
}

@end


舉例三、方法交換

@implementation UIViewController (GlobalConfig)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class class = [self class];
        
        SEL originalSelector = @selector(viewDidLoad);
        SEL swizzledSelector = @selector(mob_viewDidLoad);
        method_exchangeImplementations(class_getInstanceMethod(class, originalSelector), class_getInstanceMethod(class, swizzledSelector));
        
    });
}


- (void)mob_viewDidLoad
{
    [self mob_viewDidLoad];
    
    //。。。 下面一般是 所有 UIViewController 都要執行的內容
}

@end



參考:https://my.oschina.net/panyong/blog/298631

http://www.cnblogs.com/CoderAlex/p/5025958.html