为什么来自super init方法的instantiatie self是好的?

时间:2016-09-28 14:45:15

标签: objective-c inheritance casting

我正在编写一些代码,其中我有一个继承自MyClass类的类MySuperClassMyClass有一个属性myProperty

所以我从JSON创建了这个类的一个实例,在一个没有思想的时刻我写了这样的方法:

+ (instancetype)newFromJSON:(NSDictionary *)json {
    MyClass *myObject = [super newFromJSON:json];
    myObject.myProperty = someValue;
    return myObject;
}

请注意,MySuperClass确实有方法+ (instancetype)newFromJSON:(NSDictionary *)json

现在,这显然不起作用,因为对super newFromJSON的调用将返回MySuperClass的实例,该实例将成为myObject的实际类型。这当然会给我一个运行时错误,因为MySuperClass没有myProperty属性。

但这让我想到了什么。当我们通过调用[super init]实例化对象时,为什么我们能够做似乎相同的事情?

为什么可以这样做:

- (instancetype)init {
    self = [super init];
    if (self) {
        self.myProperty = someValue;
    }
    return self;
}

是否因为init方法在这方面受到特别对待,就像它们在许多其他方面一样?或者也许分配给self会以分配给常规变量时不会发生的方式更改实际类型?

3 个答案:

答案 0 :(得分:2)

super关键字仅指示从继承链中的哪个位置开始查找要调用的选择器(方法)。它说要开始查看当前实例的超类,而不是实例的类。

它不做的是更改隐式传递给方法的self参数的类类型。

因此,在调用[super init]时,超类中的init实现仍然会收到对MySubClass(或其他)的引用。

注意:您可以找到文档,其中指出init可能返回与调用它的类不同的类。这对于类集群很常见。这是因为init的惯用实现只返回self而不构造新实例,但允许这样做。

答案 1 :(得分:0)

澄清几点:

+ (instancetype)newFromJSON:(NSDictionary *)json {
    MyClass *myObject = [super newFromJSON:json];
    myObject.myProperty = someValue;
    return myObject;
}

当您调用[super newFromJSON:json]时,您所做的就是告诉Objective-C运行时从自己的超类开始搜索方法newFromJSON:

不会更改班级self

所以,是的,该代码是正确的,并且可以正常工作。

此外,init方法及其对super的处理还有绝对没有特殊。

答案 2 :(得分:0)

当您执行+ (instancetype)newFromJSON:(NSDictionary *)jsoninit时有一点不同。前者正在进行内存分配和新实例的初始化。 init仅完成实例的初始化。

init在编译期间是特殊的,因为它确实要求您调用[super init](它会警告您)。但实际上它是说"使用我的超类来初始化我"。

注意尽可能做你想做的事。您只需要让超类修改它分配内存的方式。您需要执行以下操作:

Parent *myObject = [[[super class] alloc] init];

这是一个有希望说明这些要点的代码示例。

让我们说你有这些课程:

@interface Parent : NSObject

@property (nonatomic, assign) NSInteger someValue;

+ (instancetype)newInstance;

- (instancetype)init;

@end

@implementation Parent

+ (instancetype)newInstance {
    Parent *myObject = [[[super class] alloc] init];

    NSLog(@"Creating new item of class %@", NSStringFromClass([myObject class]));
    return myObject;
}

- (instancetype)init {
    // This [super init] calls NSObject's init
    self = [super init];

    if (self) {
        _someValue = 1000;
    }

    return self;
}

@end

@interface ClassA : Parent

@property (nonatomic, assign) NSInteger otherValue;

@end

@implementation ClassA

+ (instancetype)newInstance {
    ClassA *myObject = [super newInstance];

    myObject.otherValue = 2000;

    return myObject;
}

- (instancetype)init {
    // This [super init] calls ClassA's init
    self = [super init];

    if (self) {
    }

    return self;
}

@end

@interface ClassB : Parent

@end

@implementation ClassB

// Default init will be Parent's

@end


@interface ClassC : Parent

@end

@implementation ClassC

- (instancetype)init {
    // We are not calling [super init];
    // NOTE: This will yield a warning since we are not calling super

    return self;
}

@end

如果您执行:

    ClassA *classA = [[ClassA alloc] init];
    ClassB *classB = [[ClassB alloc] init];
    ClassC *classC = [[ClassC alloc] init];
    Parent *newInstanceParent = [Parent newInstance];
    ClassA *newInstanceClassA = [ClassA newInstance];

    NSLog(@"classA.someValue = %ld, classB.someValue = %ld, classC.someValue = %ld", classA.someValue, classB.someValue, classC.someValue);
    NSLog(@"classA.otherValue = %ld, newInstanceClassA.otherValue = %ld", classA.otherValue, newInstanceClassA.otherValue);
    NSLog(@"newInstanceParent is %@, newInstanceClassA is %@", NSStringFromClass([newInstanceParent class]), NSStringFromClass([newInstanceClassA class]));

您将获得以下输出:

  

创建类Parent的新项目

     

创建ClassA类的新项目

     

classA.someValue = 1000,classB.someValue = 1000,classC.someValue = 0

     

classA.otherValue = 0,newInstanceClassA.otherValue = 2000

     

newInstanceParent是Parent,newInstanceClassA是ClassA