在类别中调用super与在子类中调用它相同吗?

时间:2011-05-29 13:45:01

标签: objective-c subclass categories

调用[super init]在类别中作为子类执行相同的操作吗?如果没有,有什么区别?

4 个答案:

答案 0 :(得分:14)

为了理解这一点,理解运行时对象的存储方式可能很重要。有一个类对象 1 ,它包含所有方法实现,另外,还有一个结构,其中包含实例变量的存储。类的所有实例共享一个类对象。

当您在实例上调用方法时,编译器会将其转换为对objc_msgSend的调用;在类对象中查找方法实现,然后以实例作为参数运行。

super的引用在编译时生效,运行时。当您编写[super someMethod]时,编译器会将其转换为对objc_msgSendSuper的调用,而不是通常的objc_msgSend。这开始在超类的类对象中寻找方法实现,而不是实例的类对象。 2

类别只是向类对象添加方法;它与子类化很少或没有关系。

考虑到所有这些,如果你在一个类别中引用super,它确实做了与它在类中相同的事情 - 方法实现被查找在<的类对象上em> superclass ,然后以该实例作为参数运行。

Itai的帖子更直接地回答了这个问题,但在代码中:

@interface Sooper : NSObject {}
- (void) meth;
@end

@interface Sooper ()
- (void) catMeth;
@end

@interface Subb : Sooper {}
- (void) subbMeth;
@end

@interface Subb ()
- (void) catSubbMeth;
@end

@implementation Sooper
- (void) meth {
    [super doIt];    // Looks up doIt in NSObject class object
}

- (void) catMeth {
    [super doIt];    // Looks up doIt in NSObject class object
}
@end

@implementation Subb
- (void) subbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}

- (void) catSubbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}
@end

1 请参阅Greg Parker的写作[objc explain]: Classes and meta-classes

2 需要注意的一件重要事情是,该方法不会在超类的实例上调用。这就是方法和数据分离的地方。该方法仍然在使用该实例的数据写入[super someMethod]的同一实例上调用,即子类的实例;它只是使用超类的方法实现。

因此,对[super class]的调用转到超类对象,找到名为class的方法的实现,并在实例上调用它,将其转换为等效的[self theSuperclassImplementationOfTheMethodNamedClass]。由于所有方法都返回实例的类,它被称为,你没有得到超类的类,你得到了self的类。因此,调用class对这种现象的测试很差。

这整个答案完全忽略了消息传递/方法调用的区别。这是ObjC的一个重要特征,但我认为这可能只是一个已经很尴尬的解释。

答案 1 :(得分:8)

不,他们做了不同的事情。想象一下这样的类结构:NSObject =&gt; MyObject =&gt; MySubclass,并说明MyObject上有一个名为MyCategory的类别。

现在,来自MyCategory的呼叫类似于从MyObject拨打电话,因此super指向NSObject,并且呼叫[super init]会调用NSObject }的-init方法。但是,从子类调用super指向MyObject,因此使用super进行初始化会调用MyObject的{​​{1}}方法,除非它不是被覆盖的行为与-init的行为不同。

这两种行为是不同的,所以在使用类别初始化时要小心;类别不是子类,而是当前类的添加。

答案 2 :(得分:2)

鉴于以下示例,super将调用UIView init(不是UINavigationBar init方法)

@implementation UINavigationBar (ShadowBar)
- (void)drawRect:(CGRect)rect {
    //draw the shadow ui nav bar
    [super init];
}
@end

如果您将其子类化,[super init]将调用UINavigationBar init方法。

所以,是的,如果你将在UINavigationBar init中做更多的事情(额外来自UIView),他们会做不同的事情。

答案 3 :(得分:0)

编辑:以下内容建立在一个有缺陷的前提下,请看看乔希的答案。

不删除,仍然是一个有趣的参考,可能会让你误入歧途。

他们是一回事...没有引用我们可能已经提到的任何外部讨论我应该......并且#34;用学术答案回答学术问题&#34;

@implementation categoryTestViewController (ShadowBar)
- (void)viewDidAppear:(BOOL)animated {
    //draw the shadow ui nav bar
    NSLog(@"super's class = %@, self's class %@",[super class],[self class]);
    if ([self class] == [super class]) {
        NSLog(@"yeah they are the same");
    }
}
@end

输出:

2011-05-29 08:06:16.198 categoryTest[9833:207] super's class = categoryTestViewController, self's class categoryTestViewController
2011-05-29 08:06:16.201 categoryTest[9833:207] yeah they are the same

并且调用[super viewDidAppear:]将导致不调用任何东西......不是循环,所以我不知道它在那里做了什么。