一道 Runtime 面试题的思考

这道面试题大部分应该都见过   https://halfrost.com/objc_runtime_isa_class/


@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;

@end

@implementation Sark

-(void)speak{
    NSLog(@"*******my name is %@",self.name);  
}

@end



- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"ViewController = %@ , 地址 = %p", self, &self);
    
    //这个是获得对应类
    id cls = [Sark class];
//    NSLog(@"Sark class = %@ 地址 = %p", cls, &cls);
    
    //获得类地址
    void *obj = &cls;
//    NSLog(@"Void *obj = %@ 地址 = %p", obj,&obj);
    
    [(__bridge id)obj speak];
    
}

问题在于这行代码

[(__bridge id)obj speak];

代码会执行,打印结果为"my name is viewcontroller";

obj  这时已经被强制转换为一个id 类型的对象, 它的isa 指针指向Sark类所在的地址, 所以它可以执行speak 方法.

但是为什么打印出来的是viewcontroller;

我查的资料大多是类似这样的话

这里牵涉到两个知识点:

1. 栈的入参

2.成员变量的访问

栈的入参:
这里是我理解: 栈中存放的都是对象的地址和基本数据类型; 我们每一次调用方法, 都会在栈中放入参数.

就是链接博客中的栈的参数示意图; 

成员变量的访问:

我的理解:

这个obj 有isa 指针, 指向了Sark类所在空间,但是这个obj 和new /alloc 的Sark 实例对象不一样,这个obj 在堆内是没有空间的.

访问属性

属性 = ivar(成员变量) +  setter + getter ;

通过 对象地址 + 基类大小 +  ivar 字节偏移量(offset)  得到ivar的地址, 从而访问对应的值; 

在我的理解中: 因为访问一个属性的值(ivar 的值),就是按照上述方式进行, 所以会得到一个地址, 只要这个地址有值,那么它就会打印出对应的东西;

上面那句话没有错,但是在这里没有讲清楚. 访问一个对象的成员变量 = &obj + offset(). 这里也同样如此,所以这个时候访问sark 中的name 属性时, 是沿着对象,向上移动8个字节.

为什么向上? 因为这这个对象在栈区!  栈区是从高往低排列.

而为什么是 viewcontroller ?

那么在访问name 这个属性时, 其实就是从obj 地址在栈上偏移 8个字节(NSString) , 所以 它会打印出obj 上一个的变量;

当你在 cls 之前加上一行代码后

    NSLog(@"ViewController = %@ , 地址 = %p", self, &self);
    
    NSString *str1 = @"123";

    
    //这个是获得对应类
    id cls = [Sark class];
//    NSLog(@"Sark class = %@ 地址 = %p", cls, &cls);
    
    
    //获得类地址
    void *obj = &cls;
//    NSLog(@"Void *obj = %@ 地址 = %p", obj,&obj);
    
    [(__bridge id)obj speak];
   

 打印的结果就是: *******my name is 123

 

因此, 它总是会打印出obj 这个对象栈之前8个字节(一个指针)的 地址 所 对应的 值. 

这是在OC 层面上的解释, 加入再深入一点到C或者栈, 我觉的还需要学习.

https://www.cnblogs.com/clover-toeic/p/3755401.html

但是如果你在这之前放置的是一个int/NSInteger 类型, 会发生野指针错误. 没有找到一个确定的说法, 我的猜想是: self.name 是指针便宜, 但是int/NSInteger 是基本数据类型, 通过指针访问出现了错误.

这里只是猜想, 没有进行确认,若有人知道,望不吝赐教.

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值