iOS 面试题 sel详解weak本质

1.Runtime是什么?

  • runtime 是由C C++ 汇编 实现的⼀套API,为OC语⾔加⼊了⾯向对象,运⾏时的功能

2、⽅法的本质,sel是什么?IMP是什么?两者之间的关系⼜是什么?

⽅法的本质:发送消息,消息会有以下⼏个流程

  1. 快速查找(objc_msgSend)~cache_t缓存消息
  2. 慢速查找~递归⾃⼰|⽗类~lookUpImpOrForward 
  3. 查找不到消息:动态⽅法解析~resolveInstanceMethod 
  4. 消息快速转发~forwardingTargetForSelector 
  5. 消息慢速转发~methodSignatureForSelector&forwardInvocation

sel是⽅法编号~在read_images期间就编译进⼊了内存imp就是我们函数实现指针,找imp就是找函数的过程

  • sel就相当于书本的⽬录tittle 
  • imp就是书本的⻚码

查找具体的函数就是想看这本书⾥⾯具体篇章的内容

  1. 我们⾸先知道想看什么~tittle(sel)
  2. 根据⽬录对应的⻚码(imp)
  3. 查找到具体的内容

3、能否向编译后的得到的类中增加实例变量?能否想运⾏时创建的类中添加实例变:

  1. 不能向编译后的得到的类中增加实例变量

  2. 只要内没有注册到内存还是可以添加

原因:我们编译好的实例变量存储的位置在ro,⼀旦编译完成,内存结构就完全确定就⽆法修改
        可以添加属性+⽅法 这个是在rw区内添加

4、[selfclass]和[superclass]的区别以及原理分析

 

  • [self class]:就是发送消息objc_msgSend,消息接受者是self⽅法编号:class 
  • [super class]:本质就是objc_msgSendSuper,消息的接受者还是self⽅法编号:class 只是objc_msgSendSuper会更快直接跳过self的查找

5、Runtime是如何实现weak的,为什么可以⾃动置nil

  1. 通过SideTable找到我们的weak_table 
  2. weak_table根据referent找到或者创建weak_entry_t 
  3. 然后append_referrer(entry,referrer)将我的新弱引⽤的对象加进去entry
  4. 最后weak_entry_insert 把entry加⼊到我们的weak_table

6、MethodSwizzling的坑与应⽤

应用:主要用于方法交换,使用自己方法的selct指向另一个函数的imp(函数实现),从而在调用系统函数时,调用到自己的方法从而实现HOOK方法的作用;

坑点:具体解决办法可以下载 MethodSwizzling坑Demo

1.一般情况methodSwizzling方法都会+(void)load方法中,使得方法能够更早的并且自动执行,但是有可能会有人手动调用load方法使得方法二次指回系统函数,

解决办法:使用单利方式在load方法中实现

2.交换方法自己没有实现,父类有实现;

解决办法:首先给自己添加需要交换的方法,然后再将父类的IMP给swizzling

3.交换方法中自己没有实现只用声明

解决办法:在交换之前可以先添加一个简单的实现,然后再进行交换

7、内存偏移问题

首先运行下面代码我们来看输出结果:

{
        int a = 1;
        int b = 2;
        int c = 3;
        int d = 4;
        NSLog(@"\na = %p\nb = %p\nc = %p\nd = %p\n",&a,&b,&c,&d);
}

输出结果为:可以得到结论是,栈内存是连续的;

接下来我们来看一下下面一个代码:

{
       
        //pcls ->XZPerson 类对象
        id pcls = [XZPerson class];
        void *pp= &pcls;
        [(__bridge id)pp saySomething];

        // p -> XZPerson 实例对象
        XZPerson *p = [XZPerson alloc];
        [p saySomething];
 
}

//XZPerson类中的实现
- (void)saySomething{
    NSLog(@"NB %s ",__func__);
}

上面代码是否能够正常执行:

根据运行结果我们可以看出,运行的而且输出结果一样,这说明pp 和p 是同一个对象,其中的内存指向关系为:

如果我们对saySomething方法进行中进行修改如下

{
       
        //pcls ->XZPerson 类对象
        id pcls = [XZPerson class];
        void *pp= &pcls;
        [(__bridge id)pp saySomething];

        // p -> XZPerson 实例对象
        XZPerson *p = [XZPerson alloc];
        [p saySomething];
 
}


//name 为XZPerson中只用name一个成员变量
- (void)saySomething{
    NSLog(@"NB %s name==%@",__func__,self.name);
}

打印结果为:

可以看出使用p调用的name为null  但是使用pp调用的name值为<ViewController: 0x7fb4d6d064e0> 

接下来我们继续探索为什么会是ViewController呢,我们对代码再次修改,在运行之前声明一个字符串

{
    NSString *tem = @"Alan";
    id pcls = [XZPerson class];
    void *pp= &pcls;
    [(__bridge id)pp saySomething];
    
    
    // p -> XZPerson 实例对象
    XZPerson *p = [XZPerson alloc];
    [p saySomething];
    NSLog(@"面试题");

}

打印结果为:

这个时候name访问的是上面的对象变量Alan;这说明地址进行了偏移取值;

总结

这篇文章描述了一些iOS中的一些面试题,希望对看的人有用处;

欢迎大家点赞,关注我的CSDN,我会定期做一些技术分享!未完待续。。。 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值