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

发布于 2024-10-07 04:49:22 字数 1068 浏览 7 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦幻的心爱 2024-10-14 04:49:22

从技术上讲,这是 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. Since super works a bit differently, it might mean that self is not getting retained like one would expect. One easy way to check this would be to use the calls to super as originally written, and simply leak the object referred to as self, and see if it works. If this turns out to be the problem, you might have to insert a dummy reference to self 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.

暗地喜欢 2024-10-14 04:49:22

EXC_BAD_ACCESS 的结果:

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

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

工作完美,-didRetrieveItems 和 -errorRetrieveItems 的实现位于超类中。

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

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

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

由于继承,您的类也可以有效地响应所述方法调用。只需像上面那样使用 self 调用它们即可。它会起作用,并且正是您应该这样做的!

Results in EXC_BAD_ACCESS:

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

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.

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];
 }
}];

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文