美文网首页ios
day23 self 与 super , 父类调用子类方法 -

day23 self 与 super , 父类调用子类方法 -

作者: wwwying9 | 来源:发表于2016-04-01 22:54 被阅读3275次

day23

1.self 与 super , 父类调用子类方法

1.1 self 与 super

前面也写到了self 与 super 的区别,在 OC Examination 那天中.
内容如下:

不管是 self  还是 super 其消息主体依然是  self   ,也就是说 self 和 super 指向的
是同一个对象。只是 查找方法的位置 区别,一个从本类,一个从本类的超类。

其实这段话是从网上找的,其含义并不是太明白.

    - 为什么self和super指向的依旧是self本身?
      记得好像其它语言中,self指向的就是本类,而super指向的就是父类.
    - 为什么self和super要这样去定义?

1.2 initWithFrame: 方法

今天学习的是关于自定义控件, 自定义控件时一般都需要重写构造方法来初始化该控件中的子控件,这时候最先想到的就是重写init方法,在init中创建子控件,初始化等操作.这样创建控件的时候,调用init方法就好了.这样确实可以做到.但是有人在创建控件时还想把控件里需要的参数传递进去,于是再定义一个" - (instancetype)initWithShop:(XMGShop *)shop " 方法. 或者定义一个类工厂方法 "+ (instancetype)shopViewWithShop:(XMGShop *)shop". 一运行,结果什么控件也看不到.因为上述的两个方法不会来到init方法,不会去创建子控件,所以你什么也看不到.

这时候有人会告诉你" 添加子控件,做初始化的设置,init方法内部会调用initWithFrame, 所以你只需要重写initWithFrame方法就好了", 于是把init方法改写成了initWithFrame.以运行,结果正确.

但是为什么重写init方法不行,重写initWithFrame方法就可以?

因为,init方法内部会调用initWithFrame ,更准确的说法是:父类中的init方法会调用init方法内部会调用initWithFrame方法.

这回又有点不明白了,方法是一层一层往上(父类)调用(本类中找不到,往父类中找,父类中找不到,往爷爷类中找...),你去调用父类的init方法,怎么就最终掉到了本类中的initWithFrame方法了?

有人说这是因为OC中的动态特性,就是说"在运行时才去判断对象的真实类型". 也就是说,你去调用父类的init方法,结果在父类中发现这个对象是子类(本类)的对象,于是找方法就跑到了子类的方法列表中去找了,于是就调用了子类(本类)的的方法了.

自定义控件的部分代码:

@interface XMGShopView ()
@property (nonatomic ,weak)UIImageView *iconImageView;
@property (nonatomic ,weak)UILabel *namelabel;
@end

@implementation XMGShopView

/*
//重写init方法
- (instancetype)init
{
    if (self = [super init]) {
        // 添加图片
        UIImageView *iconImageView = [[UIImageView alloc] init];
        [self addSubview:iconImageView];
        self.iconImageView = iconImageView;

        // 添加文字
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        self.namelabel = nameLabel;

    }
    return self;
}
*/

//将init改写成initWithFrame
// 添加子控件,做初始化的设置,init方法内部会调用initWithFrame
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        // 添加图片
        UIImageView *iconImageView = [[UIImageView alloc] init];
        [self addSubview:iconImageView];
        self.iconImageView = iconImageView;

        // 添加文字
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        self.namelabel = nameLabel;

    }
    return self;
}

- (instancetype)initWithShop:(XMGShop *)shop {
    if (self = [super init]) {
        self.shop = shop;
    }
    return self;
}

+ (instancetype)shopViewWithShop:(XMGShop *)shop {
    return [[self alloc] initWithShop:shop];
}
/**
 *  布局子控件,设置子控件的frame
 */
- (void)layoutSubviews
{
    // 这里一定要调用super
    [super layoutSubviews];

    CGFloat shopW = self.frame.size.width;
    CGFloat shopH = self.frame.size.height;

    self.iconImageView.frame = CGRectMake(0, 0, shopW, shopW);
    self.namelabel.frame = CGRectMake(0, shopW, shopW, shopH - shopW);

}
/**
 *  设置数据
 */
- (void)setShop:(XMGShop *)shop
{
    _shop = shop;
    self.iconImageView.image = [UIImage imageNamed:shop.icon];
    self.namelabel.text = shop.name;
}

1.3 父类调用子类方法

但这跟self 和 super 有什么关系?

要想不论用什么方法创建对象,都会掉用本类的initWithFrame方法,这样是怎么实现的呢?

想知道实现?可惜看不到源码,要是能看到源码还会有这么一大推的废话么.

去实现这个功能就可能跟 self 和 super 有关系了.

下面是模拟实现的代码,代码中定义了一个Person ,一个GoodPerson,继承与Person. (把initWithName当做initWithFrame)

并且不论用什么方法创建GoodPerson对象,都将调用GoodPerson 类中的 initWithName 方法, 就像自定义控件中,不论你用什么方法创建控件,都将调用本类中的 initWithName 方法.

其实这是因为在父类(person)中调用了[self initWithName:nil], 而此时self的值打印出来是子类的类型(GoodPerson),所以才有从父类的方法调用子类的方法这样的跳转.

所以才有这样的两句话:

  • 不管是 self 还是 super 其消息主体依然是 self ,也就是说 self 和 super 指向的 是同一个对象。只是 查找方法的位置 区别,一个从本类,一个从本类的超类。
  • 添加子控件,做初始化的设置写在initWithFrame中,init方法内部会调用initWithFrame, 所以你只需要重写initWithFrame方法,不管使用什么方法创建控件,都一定会调用initWithFrame.

完整代码:

  • Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject
-(instancetype)init;
-(instancetype)initWithName:(NSString *)name;
@end
  • Person.m
#import "Person.h"

@implementation Person
-(instancetype)init{
    if (self = [self initWithName:nil]) {
    //if (self = [super init]) {
        NSLog(@"Person --- init");

        NSLog(@"%@",self);
    }
    return self;
}
-(instancetype)initWithName:(NSString *)name{
    if (self = [super init]) {
        NSLog(@"Person --- initWithName");
      //  NSLog(@"%@",self);
    }
    return self;
}
@end
  • GoodPerson.h
#import "Person.h"

@interface GoodPerson : Person
@property(nonatomic,assign)int age;
-(instancetype)init;
-(instancetype)initWithName:(NSString *)name;

-(instancetype)initWithAge:(int)age;
+(instancetype)GoodPersonWithAge:(int)age;
@end
  • GoodPerson.m
#import "GoodPerson.h"

@implementation GoodPerson
-(instancetype)init{
    if (self = [super init]) {
        NSLog(@"GoodPerson --- init");
    }
    return self;
}
-(instancetype)initWithName:(NSString *)name{
    if (self = [super initWithName:name]) {
        NSLog(@"GoodPerson --- initWithName");
    }
    return self;
}

-(instancetype)initWithAge:(int)age{
    if (self = [super init]) {
        _age = age;
        NSLog(@"GoodPerson --- initWithAge");
    }
    return self;
}

+(instancetype)GoodPersonWithAge:(int)age{
    return [[GoodPerson alloc] initWithAge:age];
}
@end
  • main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "GoodPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        GoodPerson *p = [GoodPerson GoodPersonWithAge:10];
        NSLog(@"age = %i",p.age);
    }
    return 0;
}
/*
输出结果:
 Person --- initWithName
 GoodPerson --- initWithName
 Person --- init
 <GoodPerson: 0x100603a20>
 GoodPerson --- initWithAge
 age = 10
*/
/*
调用关系:
GoodPersonWithAge -> initWithAge (GoodPerson) ->
init(Person) -> initWithName(GoodPerson) ->
initWithName(Person) -> (NSObj 的init方法) ->  开始返回.
*/

我也是刚接触OC一个月,以上内容都是瞎写,被误导了不要打我.
其实我也想知道真相

相关文章

  • day23 self 与 super , 父类调用子类方法 -

    day23 1.self 与 super , 父类调用子类方法 1.1 self 与 super 前面也写到了se...

  • python继承二(实例)

    父类 子类一 采用父类名.方法的方式调用父类中的初始化函数" 子类二 " 使用super(子类名,self).方法...

  • python 面向对象: super()

    python 关于 super 的使用 子类对象调用父类方法 :super(B,b).hh() 子类中调用父类方法...

  • self和super的区别

    self和super的区别 self调用自己方法,super调用父类方法 self是类,super是预编译指令 [...

  • iOS Self和Super

    self调用自己方法,super调用父类方法self是类,super是预编译指令 super,class,supe...

  • iOS 中 self 和 super 的区别

    一、要点: self调用自己方法,super调用父类方法 self是类,super是预编译指令 [self cla...

  • iOS 之self和super区别

    要点: self 调用自己方法,super 调用父类方法 self是类隐藏参数,super是预编译指令 【self...

  • JavaScript零散知识点

    继承 super 在子类中调用super,会调用父类的方法; 不用super,则会覆盖父类的方法。调用本类中的方法。

  • self和super区别

    self:调用自己方法,它是类super:调用父类方法,它是预编译指令【self class】和【super cl...

  • 继承

    子类与父类有同名方法,是为覆盖,调用子类实例时,执行子类中方法,如果需要调用父类则需要super关键字

网友评论

    本文标题:day23 self 与 super , 父类调用子类方法 -

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