为什么不应该这样呢?调用-init
旨在返回具有 +1 保留计数的给定对象,并且执行“临时保留”是保证 self 在整个给定 init 方法中保持活动状态的最安全方法。考虑一下如果我们剥离 Objective-C 抽象层并变成-init
它的 IMP 解析的函数指针会发生什么:
id init(id self, SEL _cmd) {
//+0 self given requires explicit retain to guarantee lifetime
//...
//(if retained) +1 self is returned; (if not retained) +0 self is deallocated
}
如果给定self
带有 +0 保留计数的 a(这在大多数保留其参数的方法中很常见,即 setter),那么您必须保证在继承链的某处有人足够好,可以让 self 远离分配它的任何事情(最终self
有一个相当模糊的保留计数+1)。但是,如果您收到一个具有 +1 保留计数的 self,并且您自己执行了一个保留释放它,您可以通过您的-init
方法确定它仍然存在,并且您和您独自拥有self
. 如果给定的 self 不是“活着的”,那么你一定会返回 nil 而不是在释放过程中的对象。因此,上面变成了(在伪 C 中):
id init(__attribute((ns_consumed))id self, SEL _cmd) {
//implicit retain of +1 self returns self with +2
//...
//implicit release of +2 self returns self with +1
}
我喜欢称这种模式为“老式原子访问”,它用于在@synchronized {}
原子 getter 发明之前设计的 Apple 框架中。当您使用带有公共 iVar 支持的 getter 时。您经常会看到遵循该模式的方法,如下所示:
- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}
但这一切都没有触及例外即-init
和家庭的所有权规则。 -init
方法返回对象 +1,但谁真正拥有它们?好吧,分配器* 仍然在对变量的引用中占有一席之地,并且self = [super init]
实际上并没有保留任何东西(而且它还必须遵守整个“返回 +1”规则)。好吧,我不得不再次求助于伪代码,但这次是在 Objective-C 中:
- (id)init {
//self is +1 because -init must return +1
self = [super init];
//implicit [self retain]; leaves self with a +2 reference count
//...
//implicit [self autorelease]; leaves self with a +1 reference count
return self;
}
好的,现在你有一个浮动的 +1 对象被分配器声明,那么你如何“声明”它?任务,当然!隐式__strong
局部变量和__strong
属性的要点是从分配器实体中回收对象。
- (void)f {
//Freestanding +1 variable is not owned by the caller, will be deallocated when the method
//passes out of scope.
[[NSObject alloc]init];
//Implicitly __strong local captures reference away from allocator entity,
//which "autoreleases" it's ownership
//We now "own" the returned object.
NSObject *obj = [[NSObject alloc]init];
//Strong property captures reference away from local, saves the object from being deallocated
//when the method passes out of scope
self.object = obj;
}
*分配器,在这个答案的上下文中,是指最终调用malloc()
为对象分配空间的函数。