【问题标题】:Objective-C - weak property - getter autoreleases (Automatic Reference Counting)Objective-C - 弱属性 - getter autoreleases(自动引用计数)
【发布时间】:2011-11-16 08:16:47
【问题描述】:

我对 ARC 中的 weak 属性有疑问(自动引用计数)

我的理解(如有错误请指正):

weak 属性的行为类似于assign 属性,只是当该属性指向的实例被销毁时,ivar 将指向 nil。

问题:

  1. 我只是觉得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

谢谢

【问题讨论】:

    标签: objective-c automatic-ref-counting getter autorelease weak-references


    【解决方案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 获取自动释放调用并由自动释放池保留

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-11
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      相关资源
      最近更新 更多