首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >super(二) 以及内存分布

super(二) 以及内存分布

作者头像
老沙
发布2019-09-28 13:20:45
5990
发布2019-09-28 13:20:45
举报
文章被收录于专栏:老沙课堂老沙课堂

一、练习

定义一个Person类

@interface Person : NSObject
@property (nonatomic, strong) NSString *age;
- (void)test;
@end

@implementation Person
- (void)test{
    NSLog(@"age = %@",self.age);
}

ViewController 继承自UIViewController

在ViewController 书写以下代码。问是否能编译通过,如果可以输出什么是什么?

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    id cls = [Person class];
    void * temp = &cls;
    [(__bridge id)temp test];
    
    
    Person *per = [[Person alloc] init];
    [per test];
    
}

运行结果

age = <ViewController: 0x7fb25241d9c0>
age = (null)
分析
1. [super viewDidLoad]

product -> Preform Action-> assemble 查看中间层代码

.loc	1 18 5 prologue_end     ## /Users/iOS/Desktop/Demo/Demo/ViewController.m:18:5
movq	-8(%rbp), %rsi
movq	%rsi, -32(%rbp)
movq	L_OBJC_CLASSLIST_SUP_REFS_$_(%rip), %rsi
movq	%rsi, -24(%rbp)
movq	L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
leaq	-32(%rbp), %rdi
callq	_objc_msgSendSuper2

其实super 底层实现的是_objc_msgSendSuper2 而不是上一篇文章的 _objc_msgSendSuper 两个还是有区别的。我们先看一下_objc_msgSendSuper传参

// rewrite-objc 结果
_objc_msgSendSuper(
	struct {
		id self
		Class superClass
  },@selector(viewDidLoad)
)
// 底层实现 汇编结果
  _objc_msgSendSuper2(
	struct {
		id receiver
		Class current_class
  },@selector(viewDidLoad)
)

通过assemble生成的中间代码可以看出调用的是_objc_msgSendSuper2 在源码中也有对_objc_msgSendSuper2的参数介绍

	ENTRY _objc_msgSendSuper2
	UNWIND _objc_msgSendSuper2, NoFrame

	ldp	p0, p16, [x0]		// p0 = real receiver, p16 = class
	ldr	p16, [x16, #SUPERCLASS]	// p16 = class->superclass
	CacheLookup NORMAL

	END_ENTRY _objc_msgSendSuper2

从源码中 可以看到 传入参数为第一个为接收者(self) 第二个参数为 [current class]

ldr	p16, [x16, #SUPERCLASS]	// p16 = class->superclass

在上面这句代码中 获取到当前class 的superclass

2.viewDidLoad中的内存分配

我们先看图下面区域

蓝色区域为person的实例变量。per指向person实例变量

而我们的对象方法存储在class中,所以通过指针找到per ->isa -> class ->方法列表 ->具体方法

我们再看图上面区域

蓝色区域为cls变量 temp指向cls cls指向person class

从图中我们可以看出,两个在内存结构几乎一致。

我们知道 c中是通过地址与指针找到对象。可以触发person的对象方法

既然是地址寻找。那当我们调用age属性的时候,正常走的是person实例变量的地址。而在temp中,这个地址为

self,所以temp中调用的age为viewcontroller 因为他们在相同的内存位置。

二、从源码的角度看isMemberOfClass和isKindOfClass

+ (BOOL)isMemberOfClass:(Class)cls {
  // 当类传进来的时候 获取的是mate-class
    return object_getClass((id)self) == cls;
}

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

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
				// 循环遍历父类 直到nil 或者相等
        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;
}
结论

当类方法object_getClass(self) == mate-class

  • isMemberOfClass 当前对象的class是等于传进来的class
  • isKindOfClass 是否为传进来类的类或者子类
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老沙说点事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、练习
    • 分析
      • 1. [super viewDidLoad]
      • 2.viewDidLoad中的内存分配
  • 二、从源码的角度看isMemberOfClass和isKindOfClass
    • 结论
    相关产品与服务
    日志服务
    日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档