【问题标题】:arc, strong and weak instance variablesarc,强实例变量和弱实例变量
【发布时间】:2012-09-11 17:45:18
【问题描述】:

只是想完全理解 ARC。

MyView *testView = [[MyView alloc] init];

__weak MyView *weakView = testView;

[weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil];

testView = nil;

if(weakView) {
     NSLog(@"WeakView exists!");
}

我不明白为什么我的 NSLog 语句正在打印。由于weakView是对testView的弱引用,一旦testView设置为nil,它不应该指向nil吗???

谢谢!

【问题讨论】:

    标签: objective-c automatic-ref-counting


    【解决方案1】:

    addObserver 方法似乎适用于 retainautorelease 视图。这就是为什么在初始引用为零后弱引用没有立即归零的原因。只需在调试器中运行此代码:

    UIView *testView = [[UIView alloc] init];
    
    __weak UIView *weakView = testView;
    
    @autoreleasepool {
        [weakView addObserver:self forKeyPath:@"alpha" options:0 context:nil];
    }
    
    testView = nil;
    
    if(weakView) {
        NSLog(@"WeakView exists!");
    }
    

    【讨论】:

      【解决方案2】:

      它可能会也可能不会。当对象被释放时它变为 nil。您将 testView 设置为 nil 的事实仅意味着您正在释放该对象。但不保证该对象会立即被释放。

      这里的问题是您假设保留计数的给定值。您认为 alloc+init 序列为您提供了一个计数为 1 的对象,因此当您将 testView 设置为 nil 时,它变为 0 并且该对象被释放。

      您应该永远不要假设给定的保留计数。您应该始终考虑相对保留计数。 alloc+init 序列返回一个 +1 对象(不是 1 而是 +1)。当您将 set testView 设置为 nil 时,ARC 会调用 release 并将其转换为 +0 对象(不是 0,而是 +0)。这意味着您无法保证它仍然可以访问。您的弱引用可能有效,也可能无效。

      实际上发生的是,在 init 方法(或父级的链式 init 方法)内部调用了autorelease,因此您的对象还没有 0 的引用计数。它会得到它(并被释放)在下一个池耗尽时。

      编辑:

      亚当在他的回复中所说的也是正确的。

      【讨论】:

      • init 方法不会将autorelease 发送到对象。它创建保留计数 = 1 的对象。有无 ARC 都一样。
      • 有些初始化方法可以,有些则不。有一些 init 方法返回一个具有无限保留计数的对象。有一些 init 方法返回的对象不是您分配的对象。您应该从不依赖 init 方法返回一个计数正好为 1 的对象(或任何方法。事实上,甚至不应该考虑 alloc 来返回一个保证具有保留计数 1)。
      • basic rule 是:您拥有使用名称以“alloc”、“new”、“copy”或“mutableCopy”开头的方法创建的任何对象。这意味着当你完成它时,你必须releaseautorelease 它。不保证保留计数为 1,但使用这些方法至少为 1。
      • 没错。通常使用相对计数来指代。保留计数不是 1,它是 +1,这意味着您拥有该对象并最终必须释放它,自动释放它或...如果您自己是这些方法之一,则将其作为 +1 对象返回。当然,这意味着实际计数至少为 1,但可能更多。
      【解决方案3】:

      您的testView 是局部变量,ARC 下的局部变量没有精确的生命周期语义。阅读 6.1:

      http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization.precise

      这是什么意思?这意味着编译器可以为所欲为。

      当前实现在方法结束时释放testView 对象。但是如果优化器(现在,未来,...)决定生命周期已经结束,它会更快地释放它(在方法结束之前)?

      换句话说,您正在尝试依赖未定义的行为。不要这样做,不要依赖它。在这种情况下,您永远不知道对象何时真正释放 = 弱引用归零。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-07
        • 2014-03-06
        • 1970-01-01
        • 2014-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多