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 规范链接。 @user1046037 weak 在属性上只是对@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 上零弱引用为零时得到通知?

Objective-c 中 SEL 类型的属性

具有完全自定义 getter 和 setter 的属性的“弱”和“复制”属性

Objective-C——强引用弱引用(StrongWeak)

MonoTouch 中的弱事件模式