self和super到底怎么用?

开发过程中遇到一个问题.

问题简化描述如下:

有一个UIView的子类(CTestLevel),实现了init方法和initWithFrame方法,只调用了CTestLevel的init,init中只调用了[super init] , 可为什么当前类的initWithFrame被调用了?不应该是调用父类吗?怎么调用了子类的initWithFrame?

如下:

  1. 初始化一个对象
CTestLevel  *testObj = [CTestLevel  alloc] init];
@implementation CTestLevel

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        NSLog(@"initWithFrame");
    }

    return self;
}

-(instancetype)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"init");
    }

    return self;
}
@end

2.设置断点,查看调用关系
调用关系

3 查看堆栈
堆栈

查看调用关系和堆栈,
testObjc调用了init方法,然后调用了UIView的init的方法,这没有问题,
因为CTestLevel的init方法调用了[super init];

  1. 堆栈中最上层为什么又调用了CTestLevel 的initWithFrame方法呢?
  2. initWithFrame是UIView的指定初始化方法,按道理应该调用UIView的initWithFrame方法啊,为什么调用了CTestLevel的initWithFrame的初始化方法?
  3. 因为子类重写了initWithFrame,所以调用子类的initWithFrame?如果不重写就调用UIView的initWithFrame?
  4. super self 都是什么意思?

这都是怎么一个逻辑,具体是怎么实现的?

  1. 先说明Objective-C的类图结构:

类图结构
其中实心箭头表示继承关系,CTestLevel继承自UIView,UIView继承自UIResponder, …一直继承到NSObject.NSObject的父类为nil, 所有类变量到最终的父类都是nil.
虚线箭头表示所属关系:testObj属于CTestLevel类的对象,CTestLevel类属于CTestLevel元类的对象。所有的元类对象属于NSObject元类对象,NSObject元类对象属于自身.

  1. 代码说明Objective-C类的结构
    Objective-C中所有的东西都是对象,即使是类,它也是一种对象。
    testObj对象的如下表示:
/// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

objc_object 表示一个对象,其中的isa指向CTestLevel类

Class的结构体定义如下:

typedef struct objc_class *Class;

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

其中isa指向CTestLevel元类,super_class指向其父类UIView,ivars存放变量,methodLists方法列表,cache缓存方法,protocols类所遵循的协议。

  1. self和super的含义,在Objective-C中self表示当前对象(就是这个testObj对象),类似于C++里面的this指针;
    super其实是一个编译器指示符,在Runtime运行期这个关键词是不存在的。只是辅助编译器做了一些处理罢了,类似语法糖的东西。

  2. 如何向对象发消息
    testObj对象可以调用(init,initWithFrame, setHidden等方法),具体是怎么做到的?
    例如:
    当[testObj init]这样发送消息的时候,会转化为 id objc_msgSend(id theReceiver, SEL theSelector, …)来调用。其中theReceiver表示testObj对象,theSelector表示init方法. …表示参数,这里参数为空。
    简写成如下这样:obj_msgSend(testObj,init,”“)
    如果是调用哪个initWithFrame的话,大体如下:
    obj_msg_Send(testObj,@Selector(initWithFrame),frame)

那调用[super init]的时候,没有testObj这个对象了?怎么办?
[super init]会转化成如下的方法
id objc_msgSendSuper(struct objc_super *super, SEL op, …)
一个objc_super,它具体是什么呢?结构体定义如下:

struct objc_super {
    id receiver;
   Class superClass;
};

里面也有一个receiver,这个receiver就是消息的接受者,这里是self,就是这个testObj对象!
superClass: self的父类,也就是UIView.
op:表示方法;这里就是init.
一句话:去父类里面找init方法,然后给testObj发消息。对,用当前对象,调用父类的方法。

self和super的区别,就是去哪里找方法的问题,接受消息的对象还是那个对象。

举个例子说明:
类的继承关系:
类的继承关系

CTestLevel_3继承自CTestLevel_2,CTestLevel_2继承自CTestLevel_1,CTestLevel_1继承自UIView.
testObj是一个CTestLevel_3类型的对象。
CTestLevel_3实现了一个testLevel3方法,方法直接调用 : [super testLevel2];
CTestLevel_2实现了一个testLevel2方法,方法打印输出:NSStringFromClass([self class]);

因为testObj是一个CTestLevel_3的对象类型,所以输出结果[self class]是一个CTestLevel_3类型。等价于给CTestLevel_3类型的对象,发送父类的testLevel2消息。

经常遇到下面的问题:

    NSLog(@"%@\n",self); //CTestLevel_3
    NSLog(@"%@\n",[self class]);//CTestLevel_3
    NSLog(@"%@\n",[self superclass]);//CTestLevel_2
    NSLog(@"%@\n",[[self class] superclass]);//CTestLevel2 class
    NSLog(@"%@\n",[super class]);//CTestLevel3
    NSLog(@"%@\n",[super superclass]);//CTestLevel2

完。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值