美文网首页
iOS底层(六)_Runtime_2

iOS底层(六)_Runtime_2

作者: MR_詹 | 来源:发表于2019-12-21 14:51 被阅读0次

objc_msgSend

OC中的方法调用,其实都是转换为objc_msgSend函数调用
objc_msgSend的执行流程可以分3大阶段

  • 消息发送
  • 动态方法解析
  • 消息转发
objc_msgSend(消息接收者,消息名称)
// 比如:
Person *person = [Person alloc]init];
[person test];
====>objc_msgSend(person,sel_registerName('test'))

// 备注:sel_registerName('test') 与 @selector(test) 作用都是一样的,获取方法名称

//OC的方法调用:消息机制,给方法调用者发送消息
objc_msgSend如果找不到合适的方法进行调用,会报`unrecognized selector sent to instance`
消息发送 动态解析 消息转发

Super 方法

// 结构体
struct objc_super {
  id receiver,  // 消息接收者
  Class super_class,  // 消息接收者的父类(super的作用:从父类的类对象或者父类的元类对象开始找方法)
}

struct  objc_super arg = {
  self,
  class_getSuperclass(objc_getClass(类名))
}

objc_msgSendSuper(arg,@selector(方法名))


#结论:
[super message]的底层实现
1、消息接收者仍然是子类对象
2、从父类开始查找方法的实现

补充:
@synthesize
添加属性的时候时候,在实现文件中,是有这个定义的(默认不显示)
作用就是实现getter和setter方法的实现
比如:@synthesize age = _age;
就是说对age属性生成一个_age成员变量,并且生成getter方法和setter方法的实现

@dynamic
而@dynamic age;
表示:提醒编译器不要自动生成setter方法和getter的实现,不要自动生成成员变量
但是并不影响getter方法和setter方法的声明

面试题:

打印结果分别是什么?

#第一道题:
@interface MJStudent :MJPerson
@end

@interface MJPerson:NSObject
@end

@implementation MJStudent 
- (instancetype)init {
  if(self = [super init]){
    NSLog(@"%@",[self class]);  // 打印结果:MJStudent
    NSLog(@"%@",[super class]);   // 打印结果:MJStudent
    NSLog(@"%@",[self superclass]);   // 打印结果:MJPerson
    NSLog(@"%@",[super superclass]);   // 打印结果: MJPerson
  }
}
@end

#解析:
[self class] 
// 编译后:objc_msgSend(self,@selector(class));
[super class] 
// 编译后:objc_msgSendSuper(_objc_super){self,class_getSuperClass(objc_getClass('MJStudent')),@selector(class)};
编译后super与一般的消息机制有点不一样,不过两者都带有一个消息接收者(receiver)self,都是MJStudent对象。
第二,对象方法class,其实现都是在基类NSObject中,而class对象的方法底层实现是
- (Class)class {
  // objc_getClass(id) 
  // 传入的是实例对象,返回的是“类对象”
  // 传入的是类对象,返回的是“元类对象”
  return object_getClass(self);
}

[self class]和[super class]两个的消息接收者self都是MJStudent,所以返回的结果是MJStudent


superClass 编译后是
- (Class)superclass {
  return class_getSuperclass(object_getClass(self))
}








#第二道题
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[MJPerson class] isKindOfClass:[MJPerson class]];
BOOL res4 = [[MJPerson class] isMemberOfClass:[MJPerson class]];

NSLog(@"%d %d %d %d",res1,res2,res3,res4);
// 打印结果:1 0 0 0

# 解析
isKindOfClass源码
+ (BOOL)isKindOfClass:(Class)cls {
  for(Class tcls = object_getClass((id)self);tcls;tcls=tcls->superclass) {
    if(tcls == cls) return YES;
  }
  return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
  for(Class tcls = [self class];tcls;tcls=tcls->superclass) {
    if(tcls == cls) return YES;
  }
  return NO;
}

isMemberOfClass源码
+ (BOOL)isMemberOfClass:(Class)cls {
  return object_getClass((id)self) == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
  return [self class] == cls;
}


源码中:
+ isMemberOfClass 和 + isKindOfClass 都是对比消息调用者receiver的“元类”与形参是否相同(要区分“元类”和“类对象”是不一样的),而+isKindOfClass还会通过superclass遍历其父类对比
- isMemberOfClass 和 - isKindOfClass 都是对比消息调用者receiver的“类对象”与形参是否相同,不过-isKindOfClass还会通过superclass遍历其父类对比

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
消息调用者是“类对象”,形参也是一个“类对象”,编译后就是调用者的“元类”与“类对象”相比,
对比结果肯定是不一样的,但是+isKindOfClass会遍历其superclass再遍历对比,
而[NSObject class]元类的superclass指向的是NSObject的类对象,所以最后是两个NSObject类对象相比,结果是一样的

其余的三道题编译后都是“元类”与“类对象”相比,所以结果都是否(0)

【特殊的一点:基类NSObject元类对象的superClass是指向基类NSObject的类对象】
isa、superClass

相关文章

网友评论

      本文标题:iOS底层(六)_Runtime_2

      本文链接:https://www.haomeiwen.com/subject/rgrvnctx.html