假设我有一个对象,例如一个 NSString,保留计数为 5。当我调用它的副本时,我得到了该对象的一个新副本;这个新对象是否具有其原始对象的保留计数?
6 回答
copy
返回一个对象,它是对象的语义 [浅] 副本(1)。该copy
方法返回的是一个实现细节;它可能返回相同的对象,可能返回同一类的不同实例,甚至可能返回不同类的实例。
没关系。
重要的是,在手动保留/释放下,返回的对象的保留计数为 +1。不是1,而是+1。它实际上可能是 1、42、981 或 -1。没关系。
重要的是,如果您想将对象交还给系统,则必须平衡保留与 arelease
或某处。autorelease
这实际上可能不会导致它被释放;这是一个无关紧要的实现细节(无论如何,直到优化时间)。
(1)语义[shallow] copy表示返回的对象是有效的浅拷贝。当原始对象更改状态时,复制对象中包含的状态(但不在对象中包含的对象中 - 即浅部分)不会改变。对于可变对象,copy
必须实际创建某个对象的新实例——很可能是不可变的变体类——它可以包含原始状态。
对于不可变对象,该copy
方法可以简单地实现为return [self retain];
. 或者,在静态 NSStrings ( NSCFStrings
) 的情况下,它可能只是return self;
因为保留/释放/自动释放对此类字符串是无操作的。
这取决于。copy
是一种方便的方法copyWithZone:
,并且“NSCopying 协议参考”指出:
您实现此协议的选项如下:
- 在不继承 copyWithZone: 的类中 实现
NSCopying
usingalloc
and 。init...
- 通过在继承行为时
NSCopying
调用超类来实现。如果超类实现可能使用该函数,则为保留对象显式分配指针实例变量。copyWithZone:
NSCopying
NSCopyObject
NSCopying
当类及其内容不可变时,通过保留原始副本而不是创建新副本来实现。
(在所有反馈之后,我修改了以下两个语句。)
例如,NSString
是一个不可变对象,并且copy
只是保留该对象并返回指向同一对象的指针。保留对象可能会增加保留计数,但不一定(如字符串文字的情况。)
复制一个NSMutableString
可能会创建一个新对象并返回它。新对象将有自己的保留计数,独立于原始对象。
但是你不应该关心差异。使用手动引用计数,
copy
返回一个您拥有并最终必须释放的对象。使用 ARC,编译器会自动处理它。
不,复制的对象的保留计数为 1,就像新初始化的对象一样。
如果您想了解更多信息,我强烈建议您阅读内存管理指南。
如果您是 iOS 开发新手,应该先阅读iOS 应用程序编程指南,它可以很好地利用您的时间。
我刚刚注意到您没有将此标记为特定于 iOS,如果您正在为 Mac 编码,那么使用 Objective-C 编程指南可能更适合您。
要真正解决这个问题,不要考虑保留计数,考虑指针所有权(就像 ARC 一样)。
如果一个对象的“保留计数”为 5,这意味着某处的五段代码各自持有一个指向其内存地址的(强)指针。如果你copy
是那个对象,你会得到一个指向新的、复制的对象的地址的指针。其他五段代码仍然指向原始对象。只有一段代码指向新对象,所以它的“保留计数”是一。
正如其他答案中所述,内存管理指南肯定有助于使这一切变得清晰。
为什么我将“保留计数”放在引号中?因为它仅作为一般概念有用——您不应该retainCount
直接使用,否则您会收到@bbum 的消息。
当您要求 Objective-C 复制对象时,Objective-C 会使用一些巧妙的技巧,因此保留计数可能不是您认为应该的那样。
假设您有一个保留计数为 n 的对象指针 x,并调用返回对象指针 y 的复制方法。
NSObject* x = ...;
NSObject* y = [x copy];
那么规则是,如果你释放 xn 次,释放 y 一次,所有的对象都会消失。通常这是通过保持 x 不变并给 ya 保留计数 1 来实现的。
但是,如果 x 指向一个不可变对象,那么 Objective-C 可能会决定不需要进行复制。结果是 y = x。尽管如此,上面的规则仍然适用:释放 xn 次和 y 一次(即使它们是同一个对象)将释放所有涉及的对象。这是通过返回带有 +1 保留计数的 x 的复制方法来实现的。
复制像 NSMutableArray 这样的可变对象将创建一个新副本,并且保留计数将为 1,而像 NSArray 这样的复制不可变对象将指向相同的引用并将保留计数增加 1。