self and super in Objective-C

本文的参考链接:

1.iOS程序员6级考试

2.How Does Super Work?

3.官方文档

4.深入学习Objective-C


[self class]与[super class]输出什么

首先是sunnyxx博客里说的[self class][super class]输出什么的问题

#import <Foundation/Foundation.h>
#import "Father.h"
@interface Son : Father
@end

#import "Son.h"
@implementation Son
-(id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"---Son:init---");
        NSLog(@"---Son:self class = %@",[self class]);
        NSLog(@"---Son:super class = %@",[super class]);
    }
    return self;
}
@end

分别输出:

Son

Son


self关键字
self是一个隐藏参数,它是一个指向接收消息的对象的指针。

super关键字
super既不是参数也不是实例变量,而是由Objective-C编译器提供的一种标识符。当你向super发送消息的时候,实际上是在请求Objective-C向该类的超类发送消息,如果超类没有定义该消息,Objective-C 会在再上一级中寻找。找到了方法之后,则程序开始运行,由方法的实际调用者来执行该方法。

objc中消息的调用

根据官方文档,method的执行顺序是这样的。

1.基本的调用顺序

@interface XYZPerson : NSObject
- (void)sayHello;
@end

@implementation XYZPerson
- (void)sayHello {
    NSLog(@"Hello, world!");
}
@en

你生成了XYZPerson的一个实例,叫somePerson,并调用方法[somePerson sayHello],调用顺序如下图

basic message flow

2.如果在方法里面又调用了自身的其他方法,那么过程是这样的

@implementation XYZPerson
- (void)sayHello {
    [self saySomething:@"Hello, world!"];
}
- (void)saySomething:(NSString *)greeting {
    NSLog(@"%@", greeting);
}
@end

message self flow

3.看下面这张图,有两点:

(3.1)向子类发送一个只有父类实现了的消息。查找顺序是这样的,首先在子类的所有方法中查找该方法,如果不存在,则去父类的方法中查找该方法。

(3.2)下图中第二条线。(本来以为在子类中查找sayHello没找到,在父类中查找到了sayHello之后,应该调用父类的saySomething。但是由于子类覆盖了父类的saySomething方法,而方法的实际调用者是子类,那么其实最终会调用子类的saySomething

@interface XYZShoutingPerson : XYZPerson
@end

@implementation XYZShoutingPerson
- (void)saySomething:(NSString *)greeting {
    NSString *uppercaseGreeting = [greeting uppercaseString];
    NSLog(@"%@", uppercaseGreeting);
}
@end

message override

4.如果在子类中使用super调用父类的方法,那么顺序是怎样的呢?

使用[super xxx],其实就是从父类开始查找该方法,找不到则再往上一级。

@implementation XYZShoutingPerson
- (void)saySomething:(NSString *)greeting {
    NSString *uppercaseGreeting = [greeting uppercaseString];
    [super saySomething:uppercaseGreeting];
}
@end

message super


如果给Father,以及Father的父类的init都加上[self class][super class]的打印,那么结果是怎样呢


#import <Foundation/Foundation.h>
@interface GrandFather : NSObject
@end


#import "GrandFather.h"
@implementation GrandFather
-(id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"---GrandFather:init---");
        NSLog(@"---GrandFather:self class = %@",[self class]);
        NSLog(@"---GrandFather:super class = %@",[super class]);
    }
    return self;
}
@end


#import <Foundation/Foundation.h>
#import "GrandFather.h"
@interface Father : GrandFather
@end


#import "Father.h"
@implementation Father
-(id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"---Father:init---");
        NSLog(@"---Father:self class = %@",[self class]);
        NSLog(@"---Father:super class = %@",[super class]);
    }
    return self;
}
@end

#import <Foundation/Foundation.h>
#import "Father.h"
@interface Son : Father
@end

#import "Son.h"
@implementation Son
-(id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"---Son:init---");
        NSLog(@"---Son:self class = %@",[self class]);
        NSLog(@"---Son:super class = %@",[super class]);
    }
    return self;
}
@end


#import "ViewController.h"
#import "Son.h"

@interface ViewController ()
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    Son * s = [[Son alloc] init];
}
@end

所有打印的结果都是Son,原因是Son,Father,GrandFather都没有覆盖NSObject中的class方法,所以按照消息的查找顺序,在NSObject中找到该方法,由方法的实际调用者执行该方法。方法的实际调用者是Son,那么打印出来都是Son.

此处插入打印的self和super

Show Comments