我正在编写一些代码,其中我有一个继承自MyClass
类的类MySuperClass
。 MyClass
有一个属性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
会以分配给常规变量时不会发生的方式更改实际类型?
答案 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 *)json
与init
时有一点不同。前者正在进行内存分配和新实例的初始化。 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