iOS面試關(guān)于runtime

現(xiàn)在面試說(shuō)幾句就離不開(kāi)Runtime,下面我將寫(xiě)一些簡(jiǎn)單的Runtime的概念,一方面復(fù)習(xí)鞏固知識(shí),另一方面希望讀者能夠有所收獲。

Runtime是Objective-C中非常強(qiáng)大和靈活的運(yùn)行時(shí)系統(tǒng),它提供了一組API來(lái)動(dòng)態(tài)地創(chuàng)建、修改、查詢(xún)類(lèi)和對(duì)象,支持消息發(fā)送、方法交換、動(dòng)態(tài)添加方法等高級(jí)特性。下面,我們將以實(shí)際代碼案例的形式,介紹Runtime的具體用法。

動(dòng)態(tài)添加方法

動(dòng)態(tài)添加方法是Runtime的一個(gè)重要特性之一,它允許我們?cè)谶\(yùn)行時(shí)動(dòng)態(tài)地為一個(gè)類(lèi)添加新的方法。下面是一個(gè)簡(jiǎn)單的例子:

#import <objc/runtime.h>

@interface MyClass : NSObject

@end

@implementation MyClass

@end

void dynamicMethodIMP(id self, SEL _cmd)
{
    NSLog(@"添加的方法已經(jīng)被調(diào)用");
}

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        MyClass *myClass = [[MyClass alloc] init];
        
        class_addMethod([myClass class], @selector(dynamicMethod), (IMP) dynamicMethodIMP, "v@:");
        
        if ([myClass respondsToSelector:@selector(dynamicMethod)]) {
            [myClass performSelector:@selector(dynamicMethod)];
        } else {
            NSLog(@"方法未被添加");
        }
    }
    return 0;
}

在這個(gè)例子中,我們首先定義了一個(gè)MyClass類(lèi),并在運(yùn)行時(shí)動(dòng)態(tài)地為它添加了一個(gè)名為dynamicMethod的方法。我們使用class_addMethod函數(shù)來(lái)添加方法,它需要傳入一個(gè)類(lèi)對(duì)象、一個(gè)方法選擇器、一個(gè)方法的實(shí)現(xiàn)和一個(gè)方法簽名。在這個(gè)例子中,我們使用了一個(gè)名為dynamicMethodIMP的函數(shù)作為方法的實(shí)現(xiàn),它打印一條消息。最后,我們通過(guò)檢查對(duì)象是否響應(yīng)dynamicMethod方法來(lái)判斷方法是否已經(jīng)被添加,并使用performSelector方法來(lái)調(diào)用它。

方法交換

方法交換是Runtime的另一個(gè)重要特性,它允許我們?cè)谶\(yùn)行時(shí)動(dòng)態(tài)地交換兩個(gè)方法的實(shí)現(xiàn)。下面是一個(gè)簡(jiǎn)單的例子:

#import <objc/runtime.h>

@interface MyClass : NSObject

- (void)originalMethod;

@end

@implementation MyClass

- (void)originalMethod {
    NSLog(@"原始方法已經(jīng)被調(diào)用");
}

@end

@implementation MyClass (Category)

- (void)swizzledMethod {
    NSLog(@"交換后的方法已經(jīng)被調(diào)用");
    [self swizzledMethod];
}

@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        MyClass *myClass = [[MyClass alloc] init];
        
        Method originalMethod = class_getInstanceMethod([MyClass class], @selector(originalMethod));
        Method swizzledMethod = class_getInstanceMethod([MyClass class], @selector(swizzledMethod));
        method_exchangeImplementations(originalMethod, swizzledMethod);
        
        [myClass originalMethod];
    }
    return 0;
}

在這個(gè)例子中,我們首先定義了一個(gè)MyClass類(lèi),并在它的Category中添加了一個(gè)名為swizzledMethod的方法。我們使用method_exchangeImplementations函數(shù)來(lái)交換originalMethod和swizzledMethod的實(shí)現(xiàn)。最后,我們使用originalMethod方法來(lái)調(diào)用原始的方法,但實(shí)際上它會(huì)調(diào)用被交換后的swizzledMethod。

消息轉(zhuǎn)發(fā)

消息轉(zhuǎn)發(fā)是Runtime的另一個(gè)重要特性,它允許我們?cè)谶\(yùn)行時(shí)處理未知消息或方法。下面是一個(gè)簡(jiǎn)單的例子:

#import <objc/runtime.h>

@interface MyClass : NSObject

@end

@implementation MyClass

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"消息轉(zhuǎn)發(fā)已經(jīng)被觸發(fā)");
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        MyClass *myClass = [[MyClass alloc] init];
        
        [myClass performSelector:@selector(unknownMethod)];
    }
    return 0;
}

在這個(gè)例子中,我們首先定義了一個(gè)MyClass類(lèi),并重寫(xiě)了forwardInvocation和methodSignatureForSelector方法。當(dāng)對(duì)象收到一個(gè)未知的消息時(shí),它會(huì)觸發(fā)forwardInvocation方法。我們還需要重寫(xiě)methodSignatureForSelector方法來(lái)返回一個(gè)合法的方法簽名,這是消息轉(zhuǎn)發(fā)的必要步驟。最后,我們使用performSelector方法來(lái)調(diào)用一個(gè)名為unknownMethod的未知方法,這會(huì)觸發(fā)消息轉(zhuǎn)發(fā)機(jī)制并調(diào)用forwardInvocation方法。

上述代碼案例展示了Runtime的一些常用特性和API的用法,包括動(dòng)態(tài)添加方法、方法交換和消息轉(zhuǎn)發(fā),獻(xiàn)丑了各位。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容