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