iOS runtime面试题

没有比这里更全的了,看我就好了

面试官😃 :你是否了解OC中的runtime?

OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行。其动态性有runtime来支撑和实现的。通过对runtime的学习,我们可以更好的理解OC一些底层的实现,比如消息机制,分类的底层实现,利用关联对象实现分类添加属性的功能,方法交换,KVC/KVO等。

面试官😃 :你了解Objective-C的消息机制吗?

OC中的方法调用,底层是转换为objc_msgSend函数的调用。

objc_msgSend的执行流程可以分为三大阶段。

第一阶段:消息发送

        1,如果消息接收者为nil,退出。

        2,如果消息接收者不为nil,(通过isa找到当前了类)从当前类的缓存cache中查找方法,如果找到方法调用方法结束查找,如果没有找到方法,从当前类的class_rw_t中查找方法,如果找到了方法调用方法结束查找并缓存到当前类的cache中,如果当前类的class_rw_t中没有查找到方法,通过superclass找到当前类的父类重复上面查找流程。如果最终没有找到方法,就进入第二阶段动态方法解析。

第二阶段:动态方法解析(动态添加方法)

        runtime机制允许动态的添加方法,

        1,如果执行过动态方法解析,进入第三阶段消息转发阶段。

        2,如果没有执行过动态方法解析,开发者可以是使用+ (BOOL)resolveInstanceMethod:(SEL)sel (实力方法)+ (BOOL)resolveClassMethod:(SEL)sel(类方法)这两个函数来动态解析方法,标记已经动态方法解析,然后重走消息发送阶段!代码如下:

        

#import "Person.h"
#import <objc/runtime.h>

@implementation Person

void other(id self, SEL _cmd)
{
    NSLog(@"%@-%s-%s", self, sel_getName(_cmd), __func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(test)) {
        Method method = class_getInstanceMethod(self, @selector(other));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

+ (BOOL)resolveClassMethod:(SEL)sel
{
    //---
    return [super resolveClassMethod:sel];
}

第三阶段:消息转发

        1,调用- (id)forwardingTargetForSelector:(SEL)aSelector方法(把方法的实现交给其他类来实现,返回能够处理方法的对象),如果返回值不为nil(返回值是其他类),调用objc_msgSend(返回值,SEL)。

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    //交给其他类实现
    if (aSelector == @selector(test)) {
        Dog *dog = [[Dog alloc] init];
        return dog;
    }
    return [super forwardingTargetForSelector:aSelector];
}

#import "Dog.h"

@implementation Dog

- (void)test
{
    NSLog(@"%s", __func__);
}

如果返回值为nil,调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法(方法签名,返回方法签名),如果返回值不为nil,调用- (void)forwardInvocation:(NSInvocation *)anInvocation方法(封装了方法的调用),

//方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
        return signature;
    }
    return [super methodSignatureForSelector:aSelector];
}

//重组方法,封装了方法调用
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    //1,交给其他类实现
//    anInvocation.target = [[Dog alloc] init];
//    [anInvocation invoke];
    //2,尽情处理
    //交给其他类实现
    anInvocation.target = [[Dog alloc] init];
    //转发
    anInvocation.selector = @selector(other);
    //修改参数 (self _cmd 其他参数)
//    [anInvocation getArgument:<#(nonnull void *)#> atIndex:<#(NSInteger)#>]
    [anInvocation invoke];
}

如果返回值为nil,就会报错找不到方法的错误。

面试官😃 :请简述一下分类的底层实现原理?

利用OC的动态运行时,可以为类添加方法,协议等,这种方式成为分类/类别(category)

分类的实现原理:编译时将分类的方法,协议放到category_t的结构体中,在运行时动态的将category_t的内容合并到类或者元类中。

同名方法调用优先级:分类 > 本类 > 父类。(objc_msgSend)。

如果多个分类存在同名方法,运行时到底调用哪个方法有编译器决定,最后一个参与编译的方法会被调用。

面试官😃 :请简述一下KVO的底层实现原理?

利用runtime动态生成一个子类,并且让实例对象的isa指向这个全新的子类,重写setter方法。当修改实例对象的属性时,内部会调用Foundation的_NSSETXXXValueAndNotify函数

,函数内部的调用流程是:

1,willChangeValueForKey

2,父类原来的setter

3,didChangeValueForKey

4,内部触发监听器的监听方法

调用123可以手动出发KVO。

直接修改成员变量不会触发KVO,因为直接修改成员变量没有调用settter方法。

面试官😃 :请简述关联对象给分类添加属性的原理?

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值