厚积薄发 - 关于runtime的几个问题

 问题

http://blog.sunnyxx.com/2014/11/06/runtime-nuts/ 问题来源。

(1) 下面的代码输出什么? 

@implementation Son : Father
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end

2016-10-10 19:01:35.752 runtimeDemo[10090:342354] Son

2016-10-10 19:01:36.244 runtimeDemo[10090:342354] Son

当调用[self class]方法时,会转化为objc_msgSend函数,这个函数定义如下:

  1. id objc_msgSend(id self, SEL op, ...)  

  self:指向当前调用方法的对象。相当于 [son class];

    2.当调用[super class]方法时,会转化为objc_msgSendSuper,这个函数定义如下:

  1.  id objc_msgSendSuper(struct objc_super *super, SEL op, ...)  
  2.  struct objc_super {
        id receiver;
       Class superClass;
    };

其实调用super,告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。

步骤:1.构建objc_super结构体 receiver=son. superClass = Father;

   2.objc_msgSendSuper 将(super, op)传递

   3.objc_super->receiver 查找superClass(Father)的方法列表,如果没有找到,就去NSObject中查找,找到-class方法后,[objc_super->receiver(son)  class];

总结 SEL查找从继承体系中网上查找 但receiver不变。

 

(2) 下面代码的结果? 

BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];

YSE NO NO NO

isMemberOfClass: 判断对象是否为某个特定类的实例。

isKindOfClass: 判断对象是否为某类或派生类的实例。

+ (Class)class {
     return  self;
}
调用类方法,就会通过isa找到相应的元类方法列表。
- (BOOL)isKindOf:aClass
{
     Class cls;
     for  (cls = isa; cls; cls = cls->superclass) 
         if  (cls == (Class)aClass)
             return  YES;
     return  NO;
}
这个for循环中,isa指针是一层层往上。知道NSObject为止,指向了NSObject。
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
NSObject 的isa指针指向本身, [NSObject class] =NSObject。
- (BOOL)isMemberOf:aClass
{
     return  isa == (Class)aClass;
}
只是去比较当前isa指针。
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];

根据这个for循环, 我们知道,Sark的isa指针指向NSObject  [Sark class] ==Sark.第一次不相等,之后就更不相等了。

(3) 下面的代码会?Compile Error / Runtime Crash / NSLog…? 

@interface NSObject (Sark)
+ (void)foo;
@end
@implementation NSObject (Sark)
- (void)foo {
NSLog(@"IMP: -[NSObject (Sark) foo]");
}
@end
// 测试代码
[NSObject foo];
[[NSObject new] foo];

[NSObject foo];结果会调用-(void)foo

因为NSObject的元类的superClass ->NSObject 类  -方法和+方法,只是查找的体系不一样,但是实现原理是通过对象,找到对应的SEL即方法名去查找。

 

(4) 下面的代码会?Compile Error / Runtime Crash / NSLog…? 

@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Sark
- (void)speak {
NSLog(@"my name's %@", self.name);
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
id cls = [Sark class];
void *obj = &cls;
[(__bridge id)obj speak];
}
@end
 
 
 

2016-10-11 19:53:00.542 runtimeDemo[16341:945488] my name's <ViewController: 0x7fc8b3f03b70>

Propertyname最终被转换成了Ivar加入到了类的结构中,Runtime通过计算成员变量的地址偏移来寻找最终Ivar的地址。这里的原因主要是因为在C中,局部变量是存储到内存的栈区,程序运行时栈的生长规律是从地址高到地址低。C语言到头来讲是一个顺序运行的语言,随着程序运行,栈中的地址依次往下走。

 
 

转载于:https://www.cnblogs.com/JShuo/p/5950986.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值