貓貓學iOS之RunTime運用方法交換

貓貓分享,必須精品

原創文章,歡迎轉載。轉載請注明:翟乃玉的博客
地址:http://www.lxweimin.com/notebooks/4236923/latest

應用場景

在iOS開發當中,我們經常會用一些常用的系統寫方法,但是有時候這些方法讓我們并不滿意,比如說我切割字符串,系統有個方法是如下
- (NSString *)substringFromIndex:(NSUInteger)from;切割一串字符串(self)從第from個字符開始到最后,返回值是切割好的字符串
比如,我想將字符串@"123456789"從第二個字符串切割,然后打印出來,這時候我可以通過下面的幾種方法解決。

方法一:

最簡單最直接的方法,上代碼:

NSString *str = [@"123456789" substringFromIndex:2];
NSLog(@"str = %@",str);

效果:
效果

簡單粗暴,但是這個僅限于此場景,如果我想對截取后的字符做更多操作,需要每個地方都這么寫,會有很多重復代碼。

方法二:

運用分類技術,自己寫方法來實現

分類代碼:

@interface NSString (NYCategory)
- (NSString *)ny_substringFromIndex:(NSUInteger)from;
@end

@implementation NSString (NYCategory)

-(NSString *)ny_substringFromIndex:(NSUInteger)from{
    NSString *subStr = [self substringFromIndex:from];
    NSLog(@"截取后的字符串是 %@",subStr);
    return subStr;
}
@end

調用:

//首先導入分類
#import "NSString+NYCategory.h"
//調用
NSString *str = [@"123456789" ny_substringFromIndex:2];
NSLog(@"str = %@",str);

效果:


效果

這種方法可以做更多的事情,比如我想在切割的時候把當前字符串賦值成切割好的字符串,或者說給切割的字符串去掉空格等等,總之,沒有做不到 只有想不到。

  • 但是他還是有一定的缺點:
    1 對導入分類有著很高的依賴,每次用這個方法我必須都要導入自己的分類。
    2 方法名不能跟系統的一樣,有時候我們就像用系統的,并且還就是想要新東西(他喵的你有病吧。。。),于是最開始我很天真的定義分類用系統的方法名,然后調用,然后就悲劇了,如下:



    很容易造成了遞歸死循環。。。然后改成super,更悲劇了,你懂的,分類根本沒有super這一說,好吧,那就用定義NSString的子類,重寫方法,然后調用super。。。(我覺得問這問題的人真的有病。。。)

方法三:

方法三就是運用運行時的交換方法的手段來改進方法二的兩個缺點,簡單說,就是我又不想導入分類,也不想定義子類,然后還想用系統NSString的方法名,就原來怎么用我現在就怎么用,還想要這樣的效果。有這樣的好事嘛?有 RunTime...(這東西感覺基本就是為了面試官而存在的)

實現:

實現起來還是用分類,與之不同的是我們需要用到類加載方法和runtime的方法交換函數method_exchangeImplementations

分類:

@interface NSString (NYCategory)
- (NSString *)ny_substringFromIndex:(NSUInteger)from;
@end

#import "NSString+NYCategory.h"
#import <objc/message.h>

@implementation NSString (NYCategory)
// 當程序一運行,所有類會被加載,這時候會調用這個方法
+ (void)load{

    //class_getInstanceMethod是獲取類的對象的方法
    Method subStrMethod = class_getInstanceMethod([NSString class], @selector(substringFromIndex:));
    
    Method ny_subStrMethod = class_getInstanceMethod([NSString class], @selector(ny_substringFromIndex:));
    
    // 交換方法實現
    method_exchangeImplementations(subStrMethod, ny_subStrMethod);
    
}

-(NSString *)ny_substringFromIndex:(NSUInteger)from{
    NSString *subStr = [self ny_substringFromIndex:from];
    NSLog(@"截取后的字符串是 %@",subStr);
    return subStr;
}

調用:

    NSString *str = [@"123456789" substringFromIndex:2];
    NSLog(@"str = %@",str);
效果

在這里調用的時候我們并沒有導入分類,用的方法名也是系統的,但是效果卻可以做到方法二的效果。

原理:在運行的時候,當分類被加載(load方法執行)的時候,用到了運行時的交換方法實現的機制,對方法名和實現進行了對調,這里我們需要明白下面的概念:

  • 一個方法包括了 方法名方法實現
  • 方法名: 「類型是Method」可以通過運行時的方法獲取到。
    1 class_getInstanceMethod 獲取對象方法的方法編號。這里可以自己用command鍵點進去看看系統里的,他的返回值類型是
    Method**類型。
    2 class_getClassMethod 獲取類方法的方法編號。
  • 方法實現: 也就是方法具體要做的事情「類型是IMP」可以通過運行時的方法class_getMethodImplementation獲取到。
    /**
     *  獲取類方法
     *
     *  @param cls  Class:獲取哪個類方法
     *  @param name SEL:獲取方法編號,根據SEL就能去對應的類找方法
     *
     *  @return  Method 類方法名
     */
    OBJC_EXPORT Method class_getClassMethod(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
    
    /**
     *  獲取對象方法
     *
     *  @param cls  Class:獲取哪個類方法
     *  @param name SEL:獲取方法編號,根據SEL就能去對應的類找方法
     *
     *  @return  Method 對象方法名
     */
    OBJC_EXPORT Method class_getInstanceMethod(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
    
    /**
     *  獲取方法實現
     *
     *  @param cls  Class:獲取哪個類方法
     *  @param name SEL:獲取方法編號,根據SEL就能去對應的類找方法
     *
     *  @return  IMP 方法實現
     */
    OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
    __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
  • 交換方法
    對兩個方法名的方法實現進行對調,在運行的時候,當調用方法時(perform之類的),原來的時候,我們調用@selector(substringFromIndex:)方法,他會自己找到他的實現,運行,但是當我們對調之后,調用@selector(substringFromIndex:)會運行@selector(ny_substringFromIndex:)的實現
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) 
     __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

不知道當你看到這些的時候有沒有想起貓之前說的指向指針的指針,表示類的類,哈哈,這玩意我想到的是指向方法的指針,總之,先這么理解吧,歡迎大家給貓貓指正,貓本身是體育生,沒有上過計算機的專業課,一路磕磕絆絆連蒙帶猜就靠各位朋友指點教育批評才混過來的,有錯誤地方歡迎指正哈,設計底層的東西貓是真瞎。。。

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

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,776評論 0 9
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,973評論 19 139
  • 對于從事 iOS 開發人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,733評論 7 64
  • 一、前言 簡書上有哪些優質用戶?有多少大V粉絲數上萬,獲贊數上萬?小透明的自己能排到多少位?大V之間相互關注情況如...
    古柳_Deserts_X閱讀 4,542評論 52 101
  • 在這片天地里,我有自己的故事。我希望我不屬于任何一個人,任何一個地方。我只是一個游云野鶴,到哪里也沒有家。...
    沐十一閱讀 346評論 0 3