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

Mos*_*she 12 subclass objective-c categories

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

Jos*_*ell 14

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

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

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

类只是简单地向类对象添加方法; 它与子类化很少或没有关系.

考虑到所有这些,如果你引用super一个类的内部,它确实做了它在类内部的相同的事情 - 方法实现被查询在超类的类对象上,然后运行该实例作为一个论点.

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
Run Code Online (Sandbox Code Playgroud)

1参见Greg Parker的写作[objc explain]:类和元类

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

因此,调用[super class]转到超类对象,找到命名方法的实现class,并在实例上调用它,将其转换为等效的[self theSuperclassImplementationOfTheMethodNamedClass].因为所有方法都返回调用它的实例的类,所以你得不到超类的类,你得到了类self.因此,召唤class对这种现象的考验很差.

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


Ita*_*ber 8

不,他们做不同的事情.想象一下这样的类结构:NSObject=> MyObject=> MySubclass,并说你有一个MyObject被调用的类别MyCategory.

现在,调用from MyCategory类似于调用from MyObject,因此super指向NSObject并调用[super init]invokes NSObject-init方法.但是,从子类调用,super指向MyObject,所以使用superinvokes MyObject-init方法进行初始化,除非它没有被覆盖,否则它的行为与NSObjects的不同.

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