0

这是关于在我声明的接口部分中增加 NSString 类型变量的 d 保留计数值的以下程序

@property (strong,nonatomic)NSString *str1;
@property (strong, nonatomic)NSString *str2;
-(IBAction)goBtn:(id)sender;

和 ind 实现部分我定义如下

- (IBAction)goBtn:(id)sender {
   self.str1=[[NSString alloc]init];
   self.str1=self.str2;
   self.str2=[self.str1 retain];
   self.str2=[[NSString alloc]init];
   self.str2=self.str1;
   self.str1=[self.str2 retain];
   self.str2=[self.str1 retain];
   NSLog(@"retain count is %i", self.str1.retainCount);
   NSLog(@"retain count of str2 is %i", self.str2.retainCount);
}

但输出是保留计数为 0 保留计数str2为 0

为什么会这样??代码有什么问题吗???

4

2 回答 2

2

您正在向 nil 发送大量消息,这就是为什么保留计数为 0 的原因。

在这里,我再次用变量更改时的新值写下您的代码:

str1 和 str2 为零

self.str1=[[NSString alloc]init];

str1 为空字符串

self.str1=self.str2;

str1 为零

self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];

str2 为空字符串

self.str2=self.str1;

str2 为零

self.str1=[self.str2 retain];
self.str2=[self.str1 retain];

最后 str1 和 str2 都为零,给你一个零保留计数。

但即使你没有每次都用 nil 覆盖你的新字符串,你也不会得到预期的结果。让我们考虑一下:

self.str1 = [[NSString alloc] init]
self.str2 = [[NSString alloc] init]

如果您查看他们的保留计数,您将获得 18446744073709551615(在 Mac OS X 上,64 位)。如果然后查看指针的值,您会发现它们都是相等的,因此两次调用 NSString 时都会得到相同的空 NSString 对象[[NSString alloc] init]

这实际上是有道理的。NSString 对象是不可变的,这意味着一旦创建它们就永远无法更改。因此,在空字符串的多个相同副本上浪费内存是没有意义的。

其中一些共享实例从它们的 retainCount 方法返回最大可能的值,以表明它们是单例的。但不是全部。

所以对象的保留计数不是很有用。有些对象是关于它的。在真实的应用程序中,它仍然经常不是你所期望的。有时系统会保留对象一段时间,即使您自己没有保留它。

但我想您正在尝试了解保留/释放内存模型的工作原理(即使您使用的是 ARC,这也是必要的)。为此,您可以不用查询保留计数。但是你应该NSObject直接使用基类,因为它不会对保留计数器做任何特殊的技巧。而且您需要记住,一旦您将测试对象传递给某些系统方法,您的保留计数可能会在以后出现意外。永远记住永远不要在真实的应用程序中查询保留计数——这是没用的。

于 2013-07-27T07:43:04.110 回答
0

保留计数毫无意义。别担心。它涉及到很多复杂的因素,比如 NSString 是一个类集群,实现细节真的不是你的问题。

更重要的是,您的财产声明不正确。

自动保留计数 (ARC)

@property (strong, nonatomic) NSString *ARCString;

保留/释放

@property (retain, nonatomic) NSString *retainString;

进一步讨论

正如 Sven(下)指出的那样,保留和强在技术上是同义词。但是,我认为区分代码何时处于 ARC 或 Retain/Release 下很重要。一些一般的最佳实践:

仅使用 _ivar 引用 init 和 dealloc 中的 ivar,如果不使用 ARC,则在此处使用调用来保留/释放。ARC下不需要dealloc。

- (id)initWithString:(NSString *)string
{
   self = [super init];
   if (self != nil) {
      _retainString = [string retain]; // Adds 1 to retain count
   }

   return self;
}

- (void)dealloc
{
   [_retainString release]; // Decrement retain count by 1

   [super dealloc]; 
}

其余时间使用 self.ivar 调用 getter/setter。这会自动处理正确的行为。

- (void)doSomethingWithString:(NSString *)string
{
   self.retainString = string; // Adds 1 to retain count
}

如果您决定在声明的属性中覆盖 getter/setter,那么您将引用 _ivar 并手动调用保留或释放。如果使用 ARC,则无需调用保留/释放。

- (void)setRetainString:(NSString *)string
{
    if (_retainString != string) {
       [_retainString release];
       _retainString = [string retain];
    }
}

您应该始终分析您的代码,以验证您没有以明显的方式搞砸了。它通常会揭示你的逻辑失败。

于 2013-07-27T07:16:24.807 回答