3

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

4

3 回答 3

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;

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

于 2012-05-28T07:03:42.120 回答
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's init,它也调用它的 super's init,因此层次结构中的每个类都调用其构造函数。

所以,没有任何东西被转换——它只是一个指向已经存在的对象的指针,你可以返回它(99.9% 的时间)或者替换另一个对象。

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

于 2012-05-28T06:09:28.430 回答
0

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

于 2012-05-28T07:18:48.027 回答