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

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一个月,以上内容都是瞎写,被误导了不要打我.
其实我也想知道真相

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容