ios開發runtime學習三:動態添加方法(實際應用少,面試)


#import "ViewController.h"
#import "Person.h"

/* 
    1:
    Runtime(動態添加方法):OC都是懶加載機制,只要一個方法實現了,就會馬上添加到方法列表中.
    app:免費版,收費版
    QQ,微博,直播等等應用,都有會員機制
    performSelector:去執行某個方法。performSelector withObject :object為前面方法的參數
    
    2:
    美團有個面試題?有沒有使用過performSelector,什么時候使用?動態添加方法的時候使用過?怎么動態添加方法?用runtime?為什么要動態添加方法?
 */

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    _cmd:當前方法的方法編號
    
    Person *p = [[Person alloc] init];
    
    // 執行某個方法
//    [p performSelector:@selector(eat)];
    
    [p performSelector:@selector(run:) withObject:@10];
    

}

@end
#import "Person.h"
#import <objc/message.h>

@implementation Person

// 沒有返回值,也沒有參數
// void,(id,SEL)
void aaa(id self, SEL _cmd, NSNumber *meter) {
    
    NSLog(@"跑了%@", meter);
    
}

// 任何方法默認都有兩個隱式參數,self,_cmd(_cmd代表方法編號,打印結果為當前執行的方法名)
// 什么時候調用:只要一個對象調用了一個未實現的方法就會調用這個方法,進行處理
// 作用:動態添加方法,處理未實現
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    // [NSStringFromSelector(sel) isEqualToString:@"eat"];
    if (sel == NSSelectorFromString(@"run:")) {
        // eat
        // class: 給哪個類添加方法
        // SEL: 添加哪個方法
        // IMP: 方法實現 => 函數 => 函數入口 => 函數名
        // type: 方法類型:void用v來表示,id參數用@來表示,SEL用:來表示
        //aaa不會生成方法列表
        class_addMethod(self, sel, (IMP)aaa, "v@:@");
        
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];

}

//- (void)test
//{
//    // [NSStringFromSelector(sel) isEqualToString:@"eat"];
//    if (sel == NSSelectorFromString(@"eat")) {
//        // eat
//        // class: 給哪個類添加方法
//        // SEL: 添加哪個方法
//        // IMP: 方法實現 => 函數 => 函數入口 => 函數名
//        // type: 方法類型
//        class_addMethod(self, sel, (IMP)aaa, "v@:");
//        
//        return YES;
//    }
//    
//    return [super resolveInstanceMethod:sel];
//}
@end

####3.動態添加方法

* 開發使用場景:如果一個類方法非常多,加載類到內存的時候也比較耗費資源,需要給每個方法生成映射表,可以使用動態給某個類,添加方法解決。

* 經典面試題:有沒有使用performSelector,其實主要想問你有沒有動態添加過方法。

* 簡單使用

 

```

@implementation ViewController

 

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

    Person *p = [[Person alloc] init];

    

    // 默認person,沒有實現eat方法,可以通過performSelector調用,但是會報錯。

    // 動態添加方法就不會報錯

    [p performSelector:@selector(eat)];

    

}

 

 

@end

 

 

@implementation Person

// void(*)()

// 默認方法都有兩個隱式參數,

void eat(id self,SEL sel)

{

    NSLog(@"%@ %@",self,NSStringFromSelector(sel));

}

 

// 當一個對象調用未實現的方法,會調用這個方法處理,並且會把對應的方法列表傳過來.

// 剛好可以用來判斷,未實現的方法是不是我們想要動態添加的方法

+ (BOOL)resolveInstanceMethod:(SEL)sel

{

    

    if (sel == @selector(eat)) {

        // 動態添加eat方法

        

        // 第一個參數:給哪個類添加方法

        // 第二個參數:添加方法的方法編號

        // 第三個參數:添加方法的函數實現(函數地址)

        // 第四個參數:函數的類型,(返回值+參數類型) v:void @:對象->self :表示SEL->_cmd

        class_addMethod(self, @selector(eat), eat, "v@:");

        

    }

    

    return [super resolveInstanceMethod:sel];

}

@end

 

```

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM