Rob*_*b N 7 objective-c automatic-ref-counting
我想了解ARC,我正在读这个:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#consumed-parameters
它表示消耗的参数在调用之前保留,并在函数结束时释放(在函数体内).然后它说init...方法有效标记ns_consumes_self.我没有看到这一点.
Foo *foo = [[Foo alloc] initWithWhatever: x];
Run Code Online (Sandbox Code Playgroud)
所以alloc返回一个保留计数为1的对象,对吧?现在它在进入之前再次保留init,然后在结束时释放init,所以我们回到1.为什么它是这样设计的?当我想到典型的init外观时,我会更加困惑.
self = [super init];
if (self) { ... }
return self;
Run Code Online (Sandbox Code Playgroud)
因此alloc返回一个保留计数为1的对象,对吧?现在它在进入init之前再次保留,然后在init结束时释放,所以我们回到1.为什么它是这样设计的?
可能是因为初始化器可以自由地返回指向self与最初指向的对象不同的对象的指针.一种-init方法可以说:我不喜欢这个对象,我想我会替换另一个,这完全没问题.在ARC之前,这样的初始化程序将显式释放self(即使它从未保留它),然后为其分配一些其他指针.据推测,该ns_consumes_self指令将负责释放传递给初始化程序的对象,即使将self其更改为指向方法内的其他对象也是如此.
当我想到典型的init看起来像什么时,我会更加困惑.
这是一个很好的选择,这种行为可以涵盖看起来不像典型 -init方法的情况.修改self并不是典型的,只是允许的.
为什么不应该这样呢?调用-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
}
Run Code Online (Sandbox Code Playgroud)
如果给定一个self+0 保留计数(这在大多数保留其参数的方法中很常见,即设置器),那么您必须保证继承链上的某个地方有人足够好以保留 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
}
Run Code Online (Sandbox Code Playgroud)
我喜欢将这种模式称为“老式原子访问”,它在@synchronized {}原子 getter 发明之前设计的 Apple 框架中使用。当您使用由公共 iVar 支持的 getter 时。您经常会看到遵循该模式的方法,如下所示:
- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}
Run Code Online (Sandbox Code Playgroud)
但所有这些都没有触及例外-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;
}
Run Code Online (Sandbox Code Playgroud)
好的,现在你已经有了一个由分配器声明的浮动 +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;
}
Run Code Online (Sandbox Code Playgroud)
*在此答案的上下文中,分配器指的是最终调用为对象分配空间的函数。malloc()
| 归档时间: |
|
| 查看次数: |
440 次 |
| 最近记录: |