2

我最近参加关于是否lastObject返回自动释放对象的辩论。我一直以为是这样,我从来没有遇到过问题,但是,仔细想想,我大部分时间都使用这种方法,我的收藏品是参考的,所以,很明显,即使它只是一个简单的参考,代码本来可以正常工作的。因此,关于返回值的自动发布性质,我似乎是错误的(基于一些 SO 答案),但是,我试图在 Apple 的文档中找到一些关于它的内容,但没有这样做。

Apple 是否记录了它是否lastObject会自动释放它返回的对象?如果是这样,它记录在哪里?如果事实证明这是真的,他们为什么要这样做?我在上述辩论中得到的答案对我来说毫无意义,集合可以保留并自动释放对象,对吗?这样,对象在运行循环结束时仍然有效。

4

5 回答 5

7

即使它没有明确记录,它也可能lastObject具有与objectAtIndex:. objectAtIndex:不会 retain并且autorelease根据本文档返回的对象:避免导致您正在使用的对象的释放

当一个对象从一个基本集合类中移除时,它会被发送一个释放(而不是自动释放)消息。如果集合是被移除对象的唯一所有者,则被移除对象(示例中的 heisenObject)会立即被释放。

(强调我的)

考虑同一文档页面中的此示例:

heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.

在内存管理方面,释放整个数组与删除所有对象相同,因此您不能指望返回的对象在运行循环结束之前保持有效,即使在某些情况下它实际上可能没有被释放(例如文字字符串、单例、对对象的其他引用等)。

于 2012-12-31T18:07:23.713 回答
5

如果-[NSArray lastObject]自动释放对象,有理由问:“是否记录了自动释放对象,以便我可以依赖这种行为?”</p>

但如果-[NSArray lastObject]不自动释放对象,则无需询问是否记录了该行为。您必须保留返回的对象,如果您想确保它存在removeLastObject于数组的一个或一个解除分配之后。如果你不保留它,你的程序就会行为不端。文档说什么或不说什么都没有关系:确保程序在这种情况下正确运行的唯一方法是保留该对象。而且,如果它们将来发生更改lastObject以自动释放对象,您的程序仍将正常运行。

所以,什么都不知道,你应该只保留对象。

但我们可以知道别的。我们可以反汇编这个-[NSArray lastObject]方法,看看它是否自动释放。然后我们就会知道我们是否应该打扰询问文档中的内容。

-[NSArray lastObject]方法在 CoreFoundation 框架中实现。我使用Hopper反汇编了 OS X 10.8 (Mountain Lion) 64 位版本:

75e30 55              push       rbp
75e31 4889E5          mov        rbp, rsp
75e34 53              push       rbx
75e35 50              push       rax
75e36 4889FB          mov        rbx, rdi
75e39 488D3530971800  lea        rsi, qword [ds:objc_msg_count] ; @selector(count)
75e40 4889DF          mov        rdi, rbx
75e43 FF1527971800    call       qword [ds:objc_msg_count]     ; @selector(count)
75e49 4885C0          test       rax, rax
75e4c 7509            jne        0x75e57

75e4e 31C0            xor        eax, eax
75e50 4883C408        add        rsp, 0x8
75e54 5B              pop        rbx
75e55 5D              pop        rbp
75e56 C3              ret        

75e57 48FFC8          dec        rax           ; XREF=0x75e4c
75e5a 488B0D1F971800  mov        rcx, qword [ds:objc_msg_objectAtIndex_] ; @selector(objectAtIndex:)
75e61 488D3518971800  lea        rsi, qword [ds:objc_msg_objectAtIndex_] ; @selector(objectAtIndex:)
75e68 4889DF          mov        rdi, rbx
75e6b 4889C2          mov        rdx, rax
75e6e 4883C408        add        rsp, 0x8
75e72 5B              pop        rbx
75e73 5D              pop        rbp
75e74 FFE1            jmp        rcx

如果你说 x86 汇编器,你可以把它翻译成这个简单的 Objective-C 代码:

- (id)lastObject {
    NSUInteger count = self.count;
    return count == 0 ? nil : [self objectAtIndex:count-1];
}

由于文档objectAtIndex中没有自动释放对象,我们可以看到实际实现不会-[NSArray lastObject]自动释放对象。

这意味着文档中的内容并不重要:如果您希望程序正确运行,则必须保留该对象。

请注意,我并不是说您应该依赖实现细节。我只是使用实现来决定是否值得寻找文档。

于 2012-12-31T19:48:51.277 回答
3

永远不要依赖返回 +1autoreleased对象的实现,除非它被明确记录并且NSArray没有明确声明它是自动释放的。这样做的原因是它是实现定义的,并且行为可能会随着时间而改变。如果您需要一个对象的生命周期来延长返回它的对象的时间长度或直到下一个运行循环,那么您应该retain这样做。

例如,该lastObject方法可以在每个框架版本之间在以下两种实现之间自由切换。虽然从第二个实现切换到第一个实现绝不是一个好主意,但它仍然是可能的,并且会破坏在删除最后一个对象、所有对象或释放数组之前没有保留最后一个对象的任何代码。

//implementation 1
- (id)lastObject
{
    if(self.length < 1)
        return nil;

    return [self objectAtIndex:self.length - 1];
}
//implementation 2
- (id)lastObject
{
    if(self.length < 1)
        return nil;

    return [[[self objectAtIndex:self.length - 1] retain] autorelease];
}
于 2012-12-31T18:36:43.357 回答
0

如果它是自动发布的,是一个实现细节,不能可靠地回答。

lastObject 重新调整您不拥有的对象。根据可可内存命名规则:只有明确命名为“新或复制或分配”的方法(IIRC 这三个)返回新对象

见:https ://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

于 2012-12-31T17:53:06.413 回答
-1

实际上不,他们为什么要自动释放对象?

通过调用lastObject,您只需获取最后一个对象。它仍然保存在数组中。因此数组绝对不应该释放对象,也不应该为你保留对象。

如果您创建一个对象,可能会对其进行修改,然后您可以将其传递给另一个对象,则自动释放很有帮助,而无需再次担心它。

情况并非如此,它只是告诉数组中的最后一个对象是什么,保留是接收它的对象的工作。

于 2012-12-31T17:55:42.857 回答