iOS Runtime 小試(1)

runtime在平時簡單的開發中很少用到,但這個涉及到底層,做iOS的不懂runtime就等于功夫只學了招式沒有修煉內功,最多只能是個高手,懂的api多點,但運行機制不通。api學不完,但底層運行機制是不變的。所有今天主要學習了下runtime。自己寫的代碼
我先看了一個視頻 iOS runtime 分享 總結下里面講了兩個知識點。
1 交換方法實現

+ (void)load{
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = [UILabel class];
        SEL original = @selector(willMoveToSuperview:);
        SEL swizzled = @selector(myWillMoveToSuperview:);
        
        Method originalMethod   = class_getInstanceMethod(cls, original);
        Method swizzledMethod   = class_getInstanceMethod(cls, swizzled);
        
        //添加自定義的方法到類里面
        BOOL didAddMethod = class_addMethod(cls, original, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
/**
         swizzled 是存在于 UILabel 的方法列表中
         original 是存在于 UILabel 的父類方法列表中,不存在在UILabel中。 
         所以class_addMethod 是給UILabel添加一個選擇器,相當于重寫了父類的方法。
         重寫的方法名,追加另外一個函數的實現。
         */
        if (didAddMethod) {
            //方法已經添加成功  替換掉原來的方法實現
            class_replaceMethod(cls, swizzled, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else{
            //沒有添加成功    改變兩個函數的實現
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)myWillMoveToSuperview:(nullable UIView *)newSuperview{
    
    [self myWillMoveToSuperview:newSuperview];
    if (newSuperview) {
        self.backgroundColor = [UIColor yellowColor];
        [self setFont:[UIFont systemFontOfSize:13]];
    }
}

method_exchangeImplementations 改變兩個方法的實現
很多人可能會認為上面的myWillMoveToSuperview:會循環執行,其實不會的。我來捋一捋。交換地址后 系統會調用willMoveToSuperview,可這時候willMoveToSuperview 指向了 myWillMoveToSuperview,于是就執行

 {
 [self myWillMoveToSuperview:newSuperview];
    if (newSuperview) {
        self.backgroundColor = [UIColor yellowColor];
        [self setFont:[UIFont systemFontOfSize:13]];
    }
}

這時候代碼調用 myWillMoveToSuperview 其實是調用的

  [self willMoveToSuperview:newSuperview];

然后接下來執行判斷等代碼。
這里面有很多彎不好繞,要靜下心好好捋一下。


2 消息轉發

//c語言的函數  Obj-C的方法(method)就是一個至少需要兩個參數(self,_cmd)的C函數
//Since the function must take at least two arguments—self and _cmd, the second and third characters must be “@:” (the first character is the return type).
void minus(id self,SEL _cmd,NSNumber *val){
    NSLog(@"%0.2f",[[self valueForKey:@"value"] floatValue] - [val floatValue]);
}


//第一步      沒有方法 添加方法實現
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(minus:)) {
        //v@:f     返回值為void  @: the second and third characters must be “@:”
        class_addMethod([self class], sel, (IMP) minus, "v@:f");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

//第二步   指向新的方法接收者
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(uppercaseString)) {
        return @"hello world";
    }
    return [super forwardingTargetForSelector:aSelector];
}

簡單介紹下消息轉發。輕松學習之一--Objective-C消息轉發


第一步,調用一個對象的方法,進入對象方法列表中尋找,找到執行。找不到進入父類尋找。直到找到,找不到進入下一步。


第二步,給開發者一個機會 動態的給對象添加一個方法去執行。若不處理進入下一步.


第三步,進入本步說明這個對象不處理此方法的調用,這時可以讓開發者指定一個能處理此方法的對象。形象的說明就是 這件事小明沒能力做,但任務已經派發了,他認為小剛能做,就把這個任務讓小剛去做。若不處理進入下一步。


第四步,進入這一步說明問題很大了,不過系統還是給開發者最后一個機會,重新指定一個人,指定一個任務,重新包裝一下去執行。就好像這件事沒人管沒人執行,但任務下來了,得找個應急的臨時工頂一下,隨便做點啥都行,讓領導知道有人干活就好。如果臨時工也沒有找,那肯定要出大事了。系統崩潰、閃退、報錯。


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

推薦閱讀更多精彩內容

  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應用...
    Ryan___閱讀 1,962評論 1 3
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,643評論 33 466
  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,788評論 0 9
  • Runtime是什么 Runtime 又叫運行時,是一套底層的 C 語言 API,其為 iOS 內部的核心之一,我...
    SuAdrenine閱讀 900評論 0 3
  • 一、Runtime簡介 Runtime簡稱運行時。OC就是運行時機制,也就是在運行時候的一些機制,其中最主要的是消...
    林安530閱讀 1,080評論 0 2