在类接口中,我定义了一些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
也与包含类的相同。这似乎是这个问题浮出水面的附加要求(这里指的是我之前的回答,没有提到这一点(。
所以详细说明我之前的答案。如果
initXXX
是伊瓦尔id
类型- 实现与包含类相同的
Protocol
然后 Objective-C + ARC 编译器会很乐意编译代码,但无法执行它。
这是我用来测试的代码示例
@interface Dog : NSObject < Animal >
@property (nonatomic,strong) id < Animal > initState;
@end
这样的事情会导致问题,因为名称以init开头。更改名称,所有问题都会消失。
作为参考,这生成的运行时错误是
狗对象在已解除分配时过度释放
这个片段非常抽象,但这可能会在需要指定一些初始条件的地方咬你,并且很自然地命名一些 ivarinitXxx
但要注意,如果你使用 Objective-C,你就没有那么奢侈,编译器也不会警告你是错误的。
最初的错误似乎与内存分配有关,并导致我怀疑我使用自动发布池的方式,但现在我相当确信这与问题无关。