在Objective-C块的实现中是否支持 super 上的方法?
当我在超级上调用方法时,会抛出 EXC_BAD_ACCESS 错误,但只要我将这些调用从[super methodToCall]
更改为{{1}让消息向上移动响应链,它工作正常。
在块存在的类的实例中没有[self methodToCall]
的实现,但是超类中有一个(即,自己继承自的类)。
我只是好奇地了解为什么在块的实现中调用超级方法是一个问题(技术上),所以我可以在将来避免它。我怀疑它与块中如何捕获变量以及堆栈和堆有关,但我真的没有具体的想法。
注意:在块存储在属性中之后,块实现代码会被调用几秒钟,属性使用 copy ,所以我认为这不是块生命周期的问题,一切看起来都很好。此外,这只是在iPhone设备(3G)上崩溃,但在iPhone模拟器中没有崩溃。
-methodToCall
中的结果:
EXC_BAD_ACCESS
完美无缺,[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
和-didRetrieveItems
的实现属于超类。
-errorRetrievingItems
答案 0 :(得分:11)
从技术上讲,这是Objective-C运行时的问题,以及对super
的调用实际工作方式的基础机制。基本上,它们捕获作为消息接收者的对象(在所有情况下都是self
)和实现特定版本方法的类(发生方法实现的类的超类)。因为很多准备发送这样的消息都是在编译时发生的,而不是运行时,如果它与块的交互不好,我不会感到惊讶。
我会在邮件即将发送时检查self
是否仍然有效。通常,块中引用的任何对象都会自动保留。由于super
的工作方式略有不同,因此可能意味着self
没有像预期的那样得到保留。检查此问题的一种简单方法是使用最初编写的super
调用,并简单地泄漏称为self
的对象,并查看它是否有效。如果这是问题,您可能必须在块中插入一个虚拟引用self
以获得自动内存管理。
然而,从最严格的意义上讲,我不确定你是否可以永远依赖这项工作。虽然块可以捕获当前的运行时状态,但是从OOP的角度来看,它们打破封装并调用超类实现并没有意义,因为实现方法的分层级别应该是对任何外部调用代码都不透明。我会尝试找到另一种不依赖于继承层次结构的解决方案。
答案 1 :(得分: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
打电话给你。它会发现并且正是你应该如何做到的!