我刚刚修改了您的示例,在您的 NSLog 语句中添加了对 retainCount 的调用。需要注意的是,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 是 nil,发送到 nil 的消息会被忽略,所以对 [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。这是因为 NSStrings 的处理方式与大多数对象不同。这也是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。
由于显式调用retain,我们预期的第三个值增加了1。
您从 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 将所有权传递给自动释放池,并了解自动释放池将在不久的将来某个时间点释放对象(在应用程序中,池作为 runloop 循环的一部分被刷新)。
在上面的示例中,URLWithString 返回的对象的保留计数为 1。将其分配给属性会使保留计数增加 1(因此现在为 2)。然后我们刷新自动释放池(离开 @autoreleasepool { } 块的范围,保留计数回落到 1。