Objective-C init quirks



在类接口中,我定义了一些ivar

@property (strong,nonatomic) id < Protocol > initEst;   // Initial estimate

这编译没有问题,但是当我运行程序时,它崩溃了,调试器指示EXC_BAD_ACCESS[对象.cxx_destruct]作为原因。

这是怎么回事?

这一切都与 ARC 自动内存管理的规则有关。初始值设定项对如何处理返回值具有特殊规则:保留和返回。请参阅 https://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics-of-init。

一般来说,Objective-C,特别是ARC,对方法名称的含义有一些非常严格的规则。initXXX的意思是"这是一个初始值设定项"。如果这不是初始值设定项,请不要使用init前缀。

你可以完全关闭 ARC 并自己管理内存,但遵守约定更容易,而且它更适合与其他语言(如 Swift(交互的情况。

我已经对此进行了一些测试,似乎有三个条件才能出现这种特殊的怪癖。

在我的特殊情况下,ivar 的Protocol也与包含类的相同。这似乎是这个问题浮出水面的附加要求(这里指的是我之前的回答,没有提到这一点(。

所以详细说明我之前的答案。如果

  1. initXXX是伊瓦尔
  2. id类型
  3. 实现与包含类相同的Protocol

然后 Objective-C + ARC 编译器会很乐意编译代码,但无法执行它。

这是我用来测试的代码示例

@interface Dog : NSObject < Animal >
@property (nonatomic,strong) id < Animal > initState;
@end

这样的事情会导致问题,因为名称以init开头。更改名称,所有问题都会消失。

作为参考,这生成的运行时错误是

狗对象在已解除分配时过度释放

这个片段非常抽象,但这可能会在需要指定一些初始条件的地方咬你,并且很自然地命名一些 ivarinitXxx但要注意,如果你使用 Objective-C,你就没有那么奢侈,编译器也不会警告你是错误的。

最初的错误似乎与内存分配有关,并导致我怀疑我使用自动发布池的方式,但现在我相当确信这与问题无关。

最新更新