您创建的对象的所有权

Ownage of objects you create

我知道讨论过很多次,但是我在学习内存管理的时候有一点很迷茫

它表示,您拥有对象的所有权,您可以使用 alloc/copy/new/mutableCopy 或类似方法(如 allocWithSomething)创建对象。

但是,当你在 ARC 中创建像 NSArray *arr = [NSArray array]; 这样的对象时,它相当于写 NSArray *arr = [[NSArray array]autorelease];

但是,我看到很多次这样的说法 - 您拥有您创建的每个对象。但在上面的例子中,我们实际上并没有拥有对象,我们只是将它添加到 autorelease pool。因此,我们不必 retain/release 它,一旦它离开函数范围,它就会消失(正如 Apple 所说,在 "event" 之后)。

你能为我澄清一下那个时刻吗,我们真的拥有我们创建的每个对象,还是只拥有使用 alloc/copy/mutableCopy/new 创建的对象,因此将它们的保留计数增加 +1?

这是 objective-C 中所有权术语的问题。最简单的规则是,如果对象必须在我们使用完后释放,则我们拥有该对象。因此,首先所有者可以是 class,可以是方法或函数,甚至是块,还有更多。同一个对象可能有多个所有者。

释放可以通过release方法或autorelease方法调用。我们将它添加到自动释放池以延迟其释放,直到池被耗尽,这在大多数情况下是在运行循环结束时。您发布的代码对于 [[NSArray array]autorelease]; 是错误的,因为这会导致您的应用程序因过度发布而崩溃。正确的版本是 [[NSArray new] autorelease]; ,这或多或少是静态方法 array returns.

因此,如果我们暂时排除 autorelease,我们有 3 个元素:retain 将取得对象的所有权并增加保留计数,同时迫使您在某个时候释放它; release 将放弃所有权,减少保留计数,如果保留计数降为零(调用者是最后一个所有者),则可能会释放对象;对象创建规则说,所有包含 create、alloc、new、copy... 的方法或函数都会给你所有权而不保留它们,你有责任在它们上显式调用 release。

创建对象时,它的保留计数为 1。这意味着我们调用 alloc+init 或任何版本的每个对象的保留计数都为 1,并且需要被明确释放。 [NSArray array] 等所有其他静态方法只不过是 [[[NSArray alloc] init] autorelease] 的便利,需要保留这些方法才能接管所有权。

所以基本上如果你有一个 class 有一个数组指针 NSArray *_array 并且我们想要获得所有权我们必须写 _array = [someArray retain]dealloc 方法我们必须写 [_array release]。如果一个方法需要获取所有权,我们需要调用 [someArray retain] 并且当我们完成它时我们需要调用 [someArray release] 除非我们 return 对象本身我们需要调用 return [someArray autorelease]。这些是一个非常简单的规则,但其他一些情况使其极难追踪。所以 ARC 所做的就是为您在代码中插入这些调用,您无需担心它们。这些相同的程序仍然存在,就像他们在 ARC 之前所做的那样。

因此,ARC 究竟如何插入这些调用并没有真正解释,并且与版本不同。但是,如果我们再次查看您发布的示例,但让我们对其进行扩展:

- (NSArray *)foo // ARC version
{
    NSArray *arr = [NSArray array];
    for(NSObject *object in arr) NSLog(@"%@", object.description);
    arr = [arr arrayByAddingObject:@"added something"];
    return arr;
}

- (NSArray *)foo // ARC most likely behind the scenes
{
    NSArray *arr = [[NSArray array] retain]; // reatin to claim ownership
    for(NSObject *object in arr) NSLog(@"%@", object.description);
    [arr autorelease]; // need to release it as it will be lost in the next line
    arr = [[arr arrayByAddingObject:@"added something"] retain]; // the arr pointer now points to a different object. Claim the ownership of it
    return [arr autorelease]; // need to relinquish the ownership
}

- (NSArray *)foo // standart non ARC wersion
{
    NSArray *arr = [[NSArray alloc] init]; // we have the ownership by default
    for(NSObject *object in arr) NSLog(@"%@", object.description);
    NSArray *newArray = [[arr arrayByAddingObject:@"added something"] retain]; // need to explicitly retain this one as it is on the autorelease pool
    [arr release]; // We do not need it anymore
    return [newArray autorelease]; // need to relinquish the ownership
}

这可能过于简单化了,但是当你调用[NSArray数组]时,你实际上并不是在请求内存space,NSArrayclass正在为你做这件事。 NSArray class 有一个可能看起来像的方法:

  + (NSArray *) array
  {
      return [[[NSArray alloc] init] autorelease];
  }

所以它创建对象 "owns" 它,而不是你。

与其说是"owning",不如说是"responsible for"。如果您使用 alloc 和类似方法为对象请求内存,那么您有责任释放该内存。

您拥有您创建的每个对象 - 只要您希望拥有它。 "Owning" 表示您持有该对象的保留计数,并且您将释放该保留计数,或者将责任和所有权转移给其他人。

[[NSArray alloc] init...]

创建一个您当时拥有的对象,保留计数为 1。您可以将该对象传递给接管所有权的其他人。

[NSArray array]

创建并 returns 一个对象,但立即将其添加到自动释放池中。该对象返回时不属于任何人;自动释放池只是防止它被释放,直到自动释放池本身消失。任何愿意的人都可以获得该对象的所有权。当然,不止一位代码可以获得该对象的所有权。当每个人都释放所有权时,对象将消失,当自动释放池也消失时。

无论如何,ARC 会为您处理所有这些事情。