Objective-C - 弱属性 - getter autoreleases(自动引用计数)
Posted
技术标签:
【中文标题】Objective-C - 弱属性 - getter autoreleases(自动引用计数)【英文标题】:Objective-C - weak property - getter autoreleases (Automatic Reference Counting) 【发布时间】:2011-11-16 08:16:47 【问题描述】:我对 ARC 中的 weak
属性有疑问(自动引用计数)
我的理解(如有错误请指正):
weak
属性的行为类似于assign
属性,只是当该属性指向的实例被销毁时,ivar 将指向 nil。
问题:
-
我只是觉得
weak
属性的getter 保留并自动释放。难道它不应该表现得像assign
属性的getter,而getter 不会保留和自动释放吗?(请参考程序)
计划:
我在下面给出了程序的实际输出和我的预期输出。
注意 - 当我将属性从 weak
更改为 assign
时,我的预期输出得到满足
#import<Foundation/Foundation.h>
@interface A : NSObject
- (void) dealloc;
@end
@implementation A
- (void) dealloc
printf("\tinstance of A deallocated = %p\n", self);
@end
@interface B : NSObject
@property (weak) A* xa1;
- (void) dealloc;
@end
@implementation B
@synthesize xa1;
- (void) dealloc
printf("\tinstance of B deallocated = %p\n", self);
@end
int main()
B* b1 = [[B alloc] init];
@autoreleasepool //autoreleasepool 1
//block 1
A* a1 = [[A alloc] init];
printf("\ta1 = %p\n", a1);
b1.xa1 = a1;
A* a3 = b1.xa1;
printf("--- end of block 1\n");
//at this point i expected instance pointed by a1 to be destroyed
printf("--- end of autoreleasepool 1\n");
printf("---- end of main\n");
return(0);
实际输出:
a1 = 0x10d713f50
--- end of block 1
--- end of autoreleasepool 1
instance of A deallocated = 0x10d713f50
---- end of main
instance of B deallocated = 0x10d713d30
我的预期输出:
a1 = 0x10d713f50
--- end of block 1
instance of A deallocated = 0x10d713f50
--- end of autoreleasepool 1
---- end of main
instance of B deallocated = 0x10d713d30
谢谢
【问题讨论】:
【参考方案1】:在属性上提供weak
假定ivar 拥有__weak
,即它只是@synthesize
的指令。
根据http://clang.llvm.org/docs/AutomaticReferenceCounting.html §4.2,读取__weak
变量需要保留对象(当然之后释放):
在对对象左值执行左值到右值转换时发生读取。
对于 __weak 对象,当前指针被保留,然后在当前完整表达式结束时释放。这必须针对分配和指针的最终版本自动执行。 对于所有其他对象,左值加载原始语义。
它没有说明原因,但想想如果你从 __weak 变量中得到的对象在你开始使用它之前就死掉了会发生什么。弱指针的目的是确保您拥有nil
或具有已知生命周期的有效对象,这就是为什么读取其值意味着保留指针对象(然后属性的getter 将其自动释放)。
这不是 Obj-C 独有的,它是所有弱指针实现(包括引用计数和垃圾回收)的通用习惯用法。弱指针不能直接给出指针值,它们必须创建指向“持有”对象的强指针,以确保它不会在调用者开始使用它之前就死掉。在 Obj-C 中,它是 retain-autorelease;在 C++ 中,weak_ptr 先创建 shared_ptr,在垃圾收集环境中,返回一个强引用,并默默地延长对象的生命周期。
【讨论】:
感谢您的回复,我有疑问。如果我错了,请纠正我 - 使用弱属性的目的是确保不会增加寿命,只要所有者不破坏它就可以使用它。如果要增加生命周期,难道不违背使用弱指针的目的吗? @user1046037 我已经更新了我的答案,其中包含明确记录此行为的 ARC 规范链接。 @user1046037weak
在属性上只是对@synthesize
的说明。您观察到的行为是由于 __weak
读取语义:您不能将 weak 转换为指向对象的 unsafe_unretained
指针,因为它的生命周期可以随时结束,您必须在使用之前保留该对象。
我觉得 [bar doSomethingThatDestroysFoo] 无法销毁 fooPtr 指向的实例,除非包括 fooPtr 在内的所有所有者都超出范围。
@user1046037 也许这不是一个很好的例子。我们可以说,由方法(getter)返回的对象的生命周期必须至少延长到当前作用域的末尾,而对于弱指针,如果不先保留它们就不会是真的。【参考方案2】:
x1 的吸气剂看起来像:
function -[B xa1]
var_8 = rdi;
var_0 = rsi;
rdi = objc_loadWeakRetained(var_8 + *_OBJC_IVAR_$_B.xa1);
rax = [rdi autorelease];
return rax;
所以当你在
A* a3 = b1.xa1;
a1 == b1.xa1 获取自动释放调用并由自动释放池保留
【讨论】:
以上是关于Objective-C - 弱属性 - getter autoreleases(自动引用计数)的主要内容,如果未能解决你的问题,请参考以下文章
Objective-C 声明的@property 属性(非原子、复制、强、弱)
如何在 ARC 下的 Objective-C 上零弱引用为零时得到通知?
具有完全自定义 getter 和 setter 的属性的“弱”和“复制”属性