在Objective-C块的实现中调用super

11

在Objective-C块的实现中,是否支持在super上调用方法?

当我在super上调用方法时,会抛出EXC_BAD_ACCESS错误,但是一旦我将这些调用从[super methodToCall]更改为[self methodToCall]并让消息沿着响应者链向上传递,它就可以正常工作。

在包含该块的类的实例中没有-methodToCall的实现,但是在超类(即self继承的类)中有一个实现。

我只是想了解为什么在块的实现中在super上调用方法首先是个问题(技术上),以便我以后避免它。我怀疑它与块中捕获变量的方式以及堆栈和堆有关,但我确实没有明确的想法。

注意:块实现代码在存储块到属性后最多几秒钟内被调用,该属性使用copy,因此我认为这不是块的生命周期问题,所有这些看起来都很好。此外,这仅在iPhone设备(3G)上崩溃,但在iPhone模拟器中工作而不崩溃。

导致EXC_BAD_ACCESS的结果:

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

完美运行,-didRetrieveItems-errorRetrievingItems 的实现在超类中。

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];
2个回答

11

从技术上讲,这是Objective-C运行时的问题,以及关于调用super的底层机制。基本上,它们捕获了接收消息的对象(在所有情况下都是self)和实现方法特定版本的类(发生方法实现的类的超类)。由于很多为这样的消息发送做准备工作发生在编译时而不是运行时,如果它与块交互不良,我不会感到惊讶。

我会检查当消息即将发送时self是否仍然有效。通常情况下,块中引用的任何对象都会自动保留。由于super的工作方式有所不同,它可能意味着self没有像预期那样被保留。一个简单的方法来检查这个问题是使用最初编写的super调用,并简单地泄漏作为self引用的对象,看看它是否可行。如果发现这是问题,您可能需要在块内插入对self的虚拟引用以获得自动内存管理。

但严格来说,我不确定您能够永远依赖这种方法。虽然块可以捕获当前运行时状态,但从面向对象编程的角度来看,它们不应该打破封装并调用超类实现,因为方法实现的层次结构应该对任何外部调用代码是不透明的。我会尝试找到另一种不依赖于继承层次结构的解决方案。


没问题。这确实是一个有趣的问题,我之前没有想到过。 - Justin Spahr-Summers

8
产生 EXC_BAD_ACCESS 的结果:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
 if (!error) {
  [super didRetrieveItems];
 } else {
  [super errorRetrievingItems];
 }
}];

可能是编译器中的一个错误; 尝试在该块中添加 [self class]; 或任何其他对self的方法调用,它可能会起作用。

完美运行,-didRetrieveItems和-errorRetrievingItems的实现位于超类中。

[self retrieveItemsForId:idString completionHandler:^(NSError *error) {

 if (!error) {
  [self didRetrieveItems];
 } else {
  [self errorRetrievingItems];
 }
}];

我认为你可能对面向对象编程的一个基本方面感到困惑。你说在你的类中没有这些方法的实现,它们只存在于超类中。

由于继承的原因,你的类也能够有效地响应这些方法调用。只需像上面使用 self 一样调用它们即可。这样做完全可行,也是你应该采取的方法!


有时候我只是不加思考地盲打代码!由于某种原因,我一直认为它是向上移动了响应者链,没有想到它只是继承了父类的方法。这是一个非常基本的原则,却被忽略了,你说得对!感谢你让我注意到这一点。 - user836263

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接