5

我有以下示例类:

测试.h:

@interface Test : UIButton {
    NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
@property(copy) NSString *value;

测试.m:

@implementation Test
@synthesize value;
- (id)initWithValue:(NSString *)newValue {
    [super init];   
    NSLog(@"before nil value has retain count of %d", [value retainCount]);
    value = nil;
    NSLog(@"on nil value has retain count of %d", [value retainCount]);
    value = newValue;
    NSLog(@"after init value has retain count of %d", [value retainCount]);
    return self;
}

产生以下输出:

2008-12-31 09:31:41.755 Concentration[18604:20b] before nil value has retain count of 0
2008-12-31 09:31:41.756 Concentration[18604:20b] on nil value has retain count of 0
2008-12-31 09:31:41.757 Concentration[18604:20b] after init value has retain count of 2147483647

我这样称呼它:

Test *test = [[Test alloc] initWithValue:@"some text"];

value 不应该保留计数为 1 吗?我错过了什么?

谢谢你的帮助。

4

9 回答 9

22

不要看保留计数。它们没有用,只会误导你——你不能确定没有其他东西保留了一个对象,你从某个地方得到的一个对象没有被共享。

相反,专注于对象所有权并严格遵守Cocoa 内存管理规则。这样,无论 Cocoa 在幕后为您做什么优化,您的内存管理都是正确的。(例如,-copy-retain针对不可变对象实现。)

此外,了解对象的属性与对象中的实例变量之间的区别也很重要。在您的问题代码中,您正在为实例变量赋值。该实例变量就是这样:一个变量。分配给它的行为与任何其他变量分配一样。要使用该属性,您必须使用点语法或括号语法来实际调用该属性的 setter 方法:

self.value = newValue;     // this is exactly equivalent to the next line
[self setValue:newValue];  // this is exactly equivalent to the previous line

为点语法和括号语法生成的代码是相同的,都不会直接访问实例变量。

于 2009-01-01T01:59:18.467 回答
11

您正在传递一个文字字符串。编译器可能会将其分配在静态内存中并将保留计数设置为最大可能值。

尝试使用动态分配的字符串,看看会发生什么。

NSString* string = [[NSString alloc] initWithString: @"some text"];
Test* test = [[Test alloc] initWithValue: string];
于 2008-12-31T15:09:16.577 回答
4

你有一个不可变字符串的引用。赋值不需要复制值(字符串数据),因为它是不可变的。如果您执行可变操作,例如 value = [newValue uppercaseString] 那么它应该将位复制到 value 中,并且 value 的保留计数增加。

于 2008-12-31T16:02:25.863 回答
3

你传入一个字符串常量,它不能真正被释放。我觉得2147483647大概是UINT_MAX,基本就是说对象不能被释放。

于 2008-12-31T15:09:51.240 回答
3

我想你想这样做:

self.value = newValue;

这将调用属性设置器并导致复制发生。“value = newValue”只是将指针值分配给实例变量。

于 2008-12-31T15:32:59.680 回答
2

您不应该关注保留计数,只需遵循 Cocoa 内存管理规则即可。http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html

于 2009-01-01T02:53:04.973 回答
0

嗯..我们越来越近了。

看来 newValue 的保留计数也是 2147483647。

我尝试使用相同的保留计数结果动态分配字符串。

我在这里找到了一篇有用的文章:http: //www.cocoadev.com/index.pl?NSString

自由贸易协定:

@"" 返回的 NSString 是否需要释放,还是自动释放?两者都不。@""-strings 属于 NSConstantString? 类,因此就像 lisp 中的原子;他们闲逛。也就是说,如果您在代码中的两个不同位置使用 @"cow",它们将引用同一个对象。我认为 -release 或 -autorelease 对它们中的任何一个都没有任何作用。

如果我在属性上有“复制”,它不应该将目标内存的内容复制到保留计数为 1 的新内存中吗?在这种情况下,复制属性似乎什么都不做?

于 2008-12-31T15:44:07.460 回答
0
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    char *cstr = "this is a c string";

    NSString *str = [[NSString alloc] initWithUTF8String:cstr];
    NSLog(@"rc1: %d", [str retainCount]);

    [pool drain];
    return 0;
}

如果您运行上述代码,它将显示保留计数为 1

于 2009-08-12T14:24:33.860 回答
0

在 Cocoa 中,当您在同一区域内请求副本时,许多不可变对象将简单地保留自己。如果保证对象不会改变(即它的不可变性),那么精确复制是多余的。

在 Objective-C 中,常量字符串类与 Cocoa 的类是分开的NSString,尽管它可能是NSString(我不太确定)的子类。这个常量字符串类可能会覆盖NSObject的方法,比如retain,release并且dealloc它们什么都不做,也可能会覆盖,retainCount所以它总是返回相同的数字,UINT_MAX或者如此。这是因为在静态内存中创建了一个 Objective-C 常量字符串。它必须具有 Cocoa 对象的整体一般行为(使用 Cocoa 时),以便可以将其添加到数组中,用作字典的键等,除了内存管理方面,因为它的分配方式不同。

免责声明:我实际上不知道我在说什么。

于 2009-08-12T14:41:07.530 回答