菜鸟教程小白 发表于 2022-12-13 08:32:14

ios - 为什么ARC在直接将对象分配给属性时无法正常工作


                                            <p><p>我有这两个对象</p>

<pre><code>//Header file
#import &lt;Foundation/Foundation.h&gt;

@class Object2;

@interface Object1 : NSObject
@property Object2 *child;

@end

@interface Object2 : NSObject

@property (weak) Object1 *parent;

@end

// Implementation File
#import &#34;MyClass.h&#34;

@implementation Object1

-(void)dealloc{
    NSLog(@&#34;deallocating parent&#34;);
}

@end

@implementation Object2

-(void)dealloc{
    NSLog(@&#34;deallocating child&#34;);
}

@end
</code></pre>

<p>当我设置子父关系而不为子引入新变量时,</p>

<pre><code>int main(int argc, const char * argv[])
{

    @autoreleasepool {
      Object1 *p2 = [init];
      p2.child = [init];

      p2.child.parent = p2;

      NSLog(@&#34;Setting p1 to nil&#34;);
      p2=nil;
      NSLog(@&#34;Done&#34;);

    }
    return 0;
}
</code></pre>

<p>在打印“完成”之前, child 似乎没有被释放。</p>

<p>但是如果我使用一个中间变量来保存子对象,释放似乎会很好。</p>

<pre><code>@autoreleasepool {
    Object1 *p1 = [init];
    Object2 *c1 = [init];
    p1.child = c1;

    c1.parent = p1;
    c1 = nil;

    NSLog(@&#34;Setting p1 to nil&#34;);
    p1=nil;
    NSLog(@&#34;Done&#34;);


}
</code></pre>

<p>我很好奇为什么会这样。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>这里发生了很多事情,这是一个很好的探索示例。首先要意识到的是,dealloc 并没有在程序结束时发生。它发生在自动释放池的末尾(如 Julien 所述)。 ObjC 在程序终止时不运行 <code>dealloc</code>。如果您将“完成”行移到自动释放池之外,您会看到这一点。要理解的第二件大事是,这与 ARC 无关。行为与 MRC 相同。</p>

<p>那么为什么与中间体有区别?好吧,您需要考虑一下这条线的含义:</p>

<pre><code>p2.child.parent = p2;
</code></pre>

<p>真的:</p>

<pre><code>[ setParent:p2];
</code></pre>

<p>这相当于:</p>

<pre><code>id temp = ;
;
</code></pre>

<p>对 <code></code> 的调用从未在您的其他示例中发生(它调用 <code></code>,这是完全不同的)。</p>

<p>您已使用 <code>child</code> 的默认属性设置。默认设置包括 <code>atomic</code>。这意味着我们的 getter 看起来像:</p>

<pre><code>- (Object2 *)child {
return [ autorelease];
}
</code></pre>

<p>(稍微复杂一点,因为它也与 setter 同步,但这与本次讨论无关。)</p>

<p>所以现在我们有一个自动释放的 <code>temp</code> 卡在周围,它将在自动释放池的末尾被清理。如果您将 <code>(nonatomic)</code> 添加到您的属性定义中,您将看到该行为符合您的预期。</p>

<p>您的另一个示例从未对 <code></code> 进行调用,因此它不会在其上添加额外的保留/自动释放,因此会更快地被释放。</p>

<p>这里的一个教训是,在大多数情况下,<code>nonatomic</code> 是首选。 <code>atomic</code> 被设为默认值有点令人惊讶,许多 Cocoa 开发人员几乎完全使用 <code>nonatomic</code>(大多数 Apple 示例代码也是如此)。额外的保留/自动释放的想法是它在多线程代码中提供了一些保护(没有它,您的局部变量可能会在您完成之前解除分配)。在实践中,通常有比 <code>atomic</code> 更好的方法来解决这个问题(并且 <code>atomic</code> 本身并不能为您提供实际的线程安全性)。也就是说,使用 <code>atomic</code> 属性没有问题,上面的代码没有错误;它只是需要多一点内存,时间长一点。</p>

<p>如果您对这些事情感到好奇,我总是建议您查看一下汇编输出。它可能有点难以阅读,但您通常可以了解很多关于编译器选择做什么的信息。在“助手” Pane 中,只需选择“装配”(从具有“对应物”的同一菜单中)。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 为什么ARC在直接将对象分配给属性时无法正常工作,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/24705748/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/24705748/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 为什么ARC在直接将对象分配给属性时无法正常工作