自我= [超级初始化]

时间:2012-05-28 05:56:58

标签: objective-c

如果self能够存储基类实例,那么当我们返回self时,它是如何转换为派生实例的。

3 个答案:

答案 0 :(得分:4)

这就是我认为你在问的问题:假设我们有一个基类Base和一个子类Derived。如果-[Derived init]调用-[Base init]-[Base init]返回不同的实例,那么该实例不会是Base而不是Derived的实例,因此不合适吗?例如,新对象将不具有Derived可能已添加到类中的实例变量。

答案是Base不允许这样做。如果它替换原始实例,则必须以尊重原始实例的动态类型的方式执行此操作。例如,它可能会执行以下操作:

// Re-allocate with 100 extra bytes
id newSelf = NSAllocateObject([self class], 100, [self zone]);
[self release];
self = newSelf;
// ... continue to initialize ...
return self;

或者,它可以动态生成原始类的新子类,然后分配该新类的新实例。

NSString* newClassName = [NSString stringWithFormat:"%@_DynamicSubclass", NSStringFromClass([self class])];
Class newClass = objc_allocateClassPair([self class], [newClassName UTF8String], 0);
// ... further configure the new class, by adding instance variables or methods ...
objc_registerClassPair(newClass);
id newSelf = [newClass alloc];
[self release];
self = newSelf;
// ... continue to initialize ...
return self;

无论它做什么,它必须满足新实例适合在旧实例所在的任何地方使用的约束,基于其动态类型。

答案 1 :(得分:2)

self是一个隐藏的方法参数:

// this Objective-C
- (id) initWithString:(NSString*)str;

// gets implemented like this C function would be
- (objc_object*) Foo_initWithString(Foo* self, SEL _cmd, NSString* str);

它是一个指向内存的指针(用alloc分配),它已经足够大,可以容纳最派生的对象。派生最多的类调用super init,它也调用它的超级init,因此层次结构中的每个类都会调用它的构造函数。

因此,没有任何变换 - 它只是一个指向已存在对象的指针,你可以返回它(99.9%的时间)或替换另一个对象。

请注意,还有第二个隐藏参数,即选择器_cmd,在这种情况下等于@selector(initWithString:)。如果您需要当前的方法名称,也可以使用它,例如用于调试日志记录。

答案 2 :(得分:0)

此处超级实例未分配给派生实例。 self = [super init];就像告诉运行时系统在超类-init方法中查找超类方法选择器表的init方法一样,self就像支持这两个超类一样和派生类。在目标c中,包含类继承..只有实例变量是重复的。方法由层次结构中的所有类共享。如果你覆盖..你应该做self = [super init];这将引导您使用NSObject -init方法。如果我们从超类中重写-init...方法,请确保首先调用超级-init...。这就是我的理解。谢谢。