【问题标题】:objective-c memory managementObjective-C 内存管理
【发布时间】:2010-09-09 18:23:47
【问题描述】:

我对objective-c的内存管理有一些疑问,

比方说:

NSString * test= [[NSString alloc] init ]
test=@"msg";
[object setStr1: test ]; // declared as: @property(copy, readwrite)
[object setStr2: test ]; // declared as: @property(retain, readwrite)
[object setStr3: test ]; // declared as: @property(assign, readwrite)

test=@"some other string"

我认为str1 会有一份tests 内容的副本:str1 将指向包含msg 的内存(堆)的一个地址,这个地址与test 指向的地址不同.对吧?

关于str2:
1.它存储什么?,我猜指向test的地址相同,但它会将test的引用计数器增加到2。
2.当我改变测试的内容时,str2有什么?我猜它仍然指向msg

关于str3:不正确,对吧?assign 是做什么的?

谢谢。

额外问题:

NSString * test= [[NSString alloc] init ]
test=@"msg";
test=@"something";

我应该在更改内容之前发布测试吗?

【问题讨论】:

    标签: objective-c objective-c++ objective-c-runtime


    【解决方案1】:

    这里最重要的一点:赋值运算符= 从不改变(即改变)一个对象。改变一个对象只能通过发送消息来完成(例如,发送appendString:NSMutableString)。赋值运算符只是使指针指向与以前不同的对象。

    因此,这样说是不正确的:

    (1) NSString * test = [[NSString alloc] init];
    (2) test = @"msg";
    

    第 (1) 行创建一个 NSString 对象,并分配 test 指向它。第 (2) 行做同样的事情:它创建一个新的、不相关的 NSString 对象,并分配 test 指向它。现在由第 (1) 行创建的原始 NSString 没有任何指向它,并且被泄露了。

    此外,您永远不需要 alloc 字符串文字;当您使用 @"..." 语法时,编译器会隐式执行此操作。一般来说,你很少需要使用[NSString alloc](只有当你想使用各种init*方法时,例如initWithFormat:等)

    1. str1 将指向测试字符串的不同副本。 (勘误表:根据 Eiko 的说法,如果它是不可变的,接收器只会将其视为“保留”。如果您的行为正确,这没有实际区别。)
    2. str2 将指向与 test 相同的位置,并且那里的对象的保留计数将增加。
    3. str3 将指向与测试相同的位置,但保留计数不会增加。

    一般来说,字符串是不可变的,所以你不能改变它们的内容。但是,您可能需要注意 NSMutableString 的实例,它是 NSString 的子类。这就是为什么许多人建议复制字符串而不是保留它们的原因,这样,如果字符串被程序的另一部分改变,您的对象的副本将不受影响。

    【讨论】:

    • 这意味着如果测试是 NSMutableString 并且您要更改其内容 str1 仍将读取原始值,而 str2str3 将显示新值。
    • 我已经编辑了我的答案,以便更清楚地说明问题的深度,Eiko,同时还没有看到你的答案。
    • NSString 的copy 使用的秘密retain 是一个实现细节。由于 NSString 是不可变的,分配另一个实例没有意义。对于大多数类,它会生成一个真实的副本,即使使用 NSString 也可以这样处理。
    • 那么,- (NSString *) stringByAppendingFormat:(NSString *)format ... 会返回什么?
    • @Chuck - 有人提到这个细节不重要。
    【解决方案2】:

    在第二行中,您已经泄漏了内存,因为您将 test 重新分配给一个新对象并丢失了对您在第一行中创建的对象的引用。

    您对 str1 的结论是错误的,因为对于不可变类型,副本可能只返回 self(它们无论如何都不会改变,因此系统通常足够聪明,只保留一次)。

    str2 确实会指向同一个对象,只是增加保留计数。您不能更改测试的内容,因为它是不可变的。如果它是 NSMutableString,那么是的,str2 也会显示这种变化。

    assign for str3 只会“复制地址”,因此它指向同一个对象(与 str2 相同),但它不保留它,因此它不要求任何所有权/利益在那个对象中。如果你在别处释放它,str3 将指向死内存。

    奖励:正如我的介绍,是的,你泄漏了。分配@"msg" 会使您泄漏原始对象,因为@"msg" 将创建一个新对象。

    【讨论】:

    • 不,@"msg" 不会被自动释放,但它是一个常量,因此不需要释放。
    • @"msg" 在堆中存储在哪里?
    • @jhon,这些字符串文字存储在二进制文件的数据段中。当程序启动时,它们从那里被加载到内存中(就像代码一样)。这不是堆。
    • 谢谢,删除那句话。
    • 虽然 NSString 字面量不存储在堆上,但这对您编写的代码几乎没有实际影响。
    猜你喜欢
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2011-05-11
    相关资源
    最近更新 更多