我刚刚修改了您的示例以retainCount
在您的NSLog
语句中添加调用。应该注意的retainCount
是,这不是一个特别有用的方法,通常应该避免。
有关详细信息,请参阅http://whentouseretaincount.com(不要忘记向下滚动以获取更多详细信息)。
无论如何,这就是我跑的。请注意,我更改[self.str retain]
为[self.strName retain]
:
#import <Foundation/Foundation.h>
@interface SyncObjectInfo : NSObject
{
NSString *strName;
}
@property(nonatomic,retain) NSString *strName;
-(void)returnRetainCount;
@end
@implementation SyncObjectInfo
@synthesize strName;
-(void)returnRetainCount
{
NSLog(@"Que-1. what is the retainCount of self.strName = %lu", [self.strName retainCount]);
NSLog(@"Que-2. what is the retainCount of strName = %lu", [strName retainCount]);
[self.strName retain];
NSLog(@"Que-3. what is the retainCount of self.strName= %lu", [self.strName retainCount]);
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
[obj returnRetainCount];
}
}
在所有情况下,答案都是 0。这是意料之中的,因为strName
isnil
和发送到的消息nil
都被忽略了,所以调用 to[self.strName retain]
也被忽略了。
但是,如果我设置strName
一些东西,请使用以下代码:
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
obj.strName = @"Something";
[obj returnRetainCount];
}
}
然后当我重新运行时,我得到以下信息:
Que-1. what is the retainCount of self.strName = 18446744073709551615
Que-2. what is the retainCount of strName = 18446744073709551615
Que-3. what is the retainCount of self.strName= 18446744073709551615
保留计数为 18446744073709551615。这是因为NSString
s 的处理方式与大多数对象不同。retainCount
这是不是很有用的原因之一。
如果我们将 更改NSString
为NSURL
如下:
@interface SyncObjectInfo : NSObject
{
NSURL *strName;
}
@property(nonatomic,retain) NSURL *strName;
// snip
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj = [SyncObjectInfo new];
obj.strName = [NSURL URLWithString:@"http://stackoverflow.com"];
[obj returnRetainCount];
}
}
重新运行我们得到:
Que-1. what is the retainCount of self.strName = 2
Que-2. what is the retainCount of strName = 2
Que-3. what is the retainCount of self.strName= 3
前两种情况是一样的。返回的对象+URLWithString
被保留但自动释放,然后分配给属性并再次保留。在未来的某个时候,自动释放池将被刷新,保留计数将降至 1。
我们期望的第三个值增加了 1,因为显式调用retain
.
您从 Apple 文档中理解保留计数应为 1(而不是问题 1 和 2 中的 2)在技术上是不正确的,但在概念上是正确的。该对象已被自动释放(实际上是该对象将在不久的将来释放的承诺)。
我们可以通过冲洗池来研究自动释放池的影响。我已经修改了main
函数以在调用之前刷新自动释放池returnRetainCount
。
int main(int argc, char *argv[]) {
@autoreleasepool {
SyncObjectInfo *obj;
@autoreleasepool {
obj = [SyncObjectInfo new];
obj.strName = [NSURL URLWithString:@"http://stackoverflow.com"];
}
[obj returnRetainCount];
}
}
这次的输出是:
Que-1. what is the retainCount of self.strName = 1
Que-2. what is the retainCount of strName = 1
Que-3. what is the retainCount of self.strName= 2
这更符合您的预期。那么发生了什么?
当NSURL
对象由该URLWithString
方法创建时,它的保留计数为 1。但是,NSURL
该类需要放弃该对象的所有权。如果它release
在返回之前调用此对象,则保留计数将达到 0,并且该对象将在返回之前被释放。
相反,该URLWithString
方法调用autorelease
对象。自动释放将对象添加到自动释放池。基本上,NSURL
将所有权传递给自动释放池,并了解自动释放池将在不久的将来某个时间点释放对象(在应用程序中,池作为运行循环周期的一部分被刷新)。
在上面的示例中,返回的对象URLWithString
的保留计数为 1。将其分配给属性会使保留计数增加 1(因此现在为 2)。然后我们刷新自动释放池(通过离开@autoreleasepool { }
块的范围并且保留计数回落到 1。