在 Objective-C 块的实现中调用 super
Objective-C 块的实现是否支持调用 super 上的方法?
当我在 super 上调用方法时,会抛出 EXC_BAD_ACCESS 错误,但一旦我将这些调用从 [super methodToCall]
更改为 < code>[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
和 -errorRetrieveItems
的实现位于超类中。
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
Is calling a method on super supported in the implementation of an Objective-C block?
When I was calling a method on super an EXC_BAD_ACCESS error would be thrown but as soon as I changed those calls from [super methodToCall]
to [self methodToCall]
and let the message move up the responder chain it worked fine.
There is no implementation of -methodToCall
in the instance of the class that the block exists in, but there is one in the superclass (that is, the class that self inherits from).
I'm just curious to learn the details as to why calling a method on super inside the implementation of a block was a problem in the first place (technically) so I can avoid it in the future. I have a suspicion it is related to how the variables are captured in the block and something about the stack and the heap, but I really have no concrete idea.
Note: the block implementation code is called up to a few seconds after the block is stored in a property, the property uses copy so I don't think it's a problem with the block's lifecycle, that all looks to be fine. Also, this was only crashing on the iPhone device (3G) but was working without crashing in the iPhone Simulator.
Results in EXC_BAD_ACCESS
:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
Works perfect, implementations of -didRetrieveItems
and -errorRetrievingItems
are in the super-class.
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从技术上讲,这是 Objective-C 运行时以及调用
super
实际工作方式的底层机制的问题。基本上,它们捕获消息接收者的对象(在所有情况下都是 self)和实现该方法的特定版本的类(方法实现所在类的超类) )。因为此类消息发送的许多准备工作都是在编译时而不是运行时进行的,所以如果它与块交互不良,我不会感到惊讶。当消息即将发送时,我会检查
self
是否仍然有效。通常,块中引用的任何对象都会自动保留。由于super
的工作方式有点不同,这可能意味着self
没有像人们期望的那样被保留。检查这一点的一种简单方法是使用最初编写的对 super 的调用,并简单地泄漏称为 self 的对象,然后查看它是否有效。如果这确实是问题所在,您可能必须在块内插入对 self 的虚拟引用才能实现自动内存管理。然而,从最严格的意义上来说,我不确定您是否可以永远依赖它。尽管块可以捕获当前运行时状态,但它们打破封装并调用超类实现并没有真正意义(从 OOP 角度来看),因为实现方法的分层级别应该是对任何外部调用代码都是不透明的。我会尝试找到另一个不依赖于继承层次结构的解决方案。
Technically, this is an issue with the Objective-C runtime, and the underlying mechanics of how calls to
super
actually work. Basically, they capture both the object which is the recipient of the message (self
in all cases) and the class which implements the specific version of the method (the superclass of the class in which the method implementation occurs). Because a lot of the preparation for such a message send happens at compile-time, not runtime, I wouldn't be surprised if it interacted badly with blocks.I would check to see if
self
is still valid when the message is about to be sent. Normally, any objects referenced in a block are automatically retained. Sincesuper
works a bit differently, it might mean thatself
is not getting retained like one would expect. One easy way to check this would be to use the calls tosuper
as originally written, and simply leak the object referred to asself
, and see if it works. If this turns out to be the problem, you might have to insert a dummy reference toself
within the block to get that automatic memory management.In the strictest sense, however, I'm not sure you can depend on this working forever and always. Although blocks can capture the current runtime state, it doesn't really make sense (from an OOP perspective) for them to break encapsulation and invoke superclass implementations, since the hierarchical level at which methods are implemented should be opaque to any external calling code. I would try to find another solution which doesn't depend on the inheritance hierarchy.
可能是由于编译器中的错误;尝试在该块中添加
[self class];
或任何其他对 self 的方法调用,它可能会起作用。我认为您可能对面向对象编程的基本方面之一感到困惑。您说您的类中没有这些方法的实现,它们仅存在于超类中。
由于继承,您的类也可以有效地响应所述方法调用。只需像上面那样使用
self
调用它们即可。它会起作用,并且正是您应该这样做的!Probably due to a bug in the compiler; try adding
[self class];
or any other method call to self in that block and it'll probably work.I think you may be confused about one of the fundamental aspects of object oriented programming. You say that there are no implementations of those methods in your class, they exist only in the superclass.
Because of inheritance, your class effectively responds to said method calls, too. Just call 'em as you do above using
self
. It will work find and is exactly how you should be doing it!