【发布时间】:2011-05-13 07:26:23
【问题描述】:
如果我将 NSString 设置为属性
@property (copy) NSString* name;
我一直想使用(复制),这样如果它的值发生变化,所有具有该字符串的对象仍然具有旧值(指定here)。
但是,如果我的 NSString 不是类属性,而只是在代码中声明,会发生什么?在这种情况下,每次我分配新值时都会保留或复制吗?
谢谢
【问题讨论】:
标签: objective-c ios
如果我将 NSString 设置为属性
@property (copy) NSString* name;
我一直想使用(复制),这样如果它的值发生变化,所有具有该字符串的对象仍然具有旧值(指定here)。
但是,如果我的 NSString 不是类属性,而只是在代码中声明,会发生什么?在这种情况下,每次我分配新值时都会保留或复制吗?
谢谢
【问题讨论】:
标签: objective-c ios
这取决于你如何声明它。您应该阅读有关内存管理的documentation。基本上规则是:
NSString *aString = [NSString stringWithString:@"Hello"];
NSString *bString = [NSString stringWithFormat:@"%@", @"Hello"];
在这些情况下,不会复制或保留字符串。它是自动释放的,这意味着它将在下次自动释放池耗尽时自动释放。您不必对它们调用 release 方法。 (因此分配一个新值不会导致它泄漏。)
NSString *cString = [[NSString alloc] initWithFormat:@"%@", @"Hello"];
[cString release];
根据 Objective C 约定,使用 alloc 且保留计数为 1 的方法不会自动释放,因此您需要显式释放它们。分配新值而不释放旧值会导致泄漏。
您还可以在字符串上显式调用“复制”方法或“保留”方法。无论哪种情况,新字符串的保留计数都为 1,并且不会自动释放,因此您需要在分配新值之前对其调用 release 方法。
NSString *dString = [cString retain];
NSString *eString = [cString copy];
...
[dString release];
[eString release];
如果它是一个属性,并且您使用 self.variableName,这将由您处理(通过使用 @synthesize 生成的 getter 和 setter)。如果你明确地这样做,你必须确保在你调用了保留或复制的变量上调用 release。
编辑:正如下面的一些评论员所指出的,从“所有权”的角度考虑管理通常是描述这些想法的首选,而不是保留数量。
【讨论】:
alloc而不是init开头的方法,创建所有权,而不是保留计数1。init对内存没有任何影响,你应该避免考虑保留算作绝对数。但我没有对你投反对票。
@"Hello" 不会自动释放。你不拥有它们,但它们永远不会消失。给您保留对象的不是-init,而是以 alloc 或 new 开头或包含副本的方法(阅读您链接到的规则)。最后,复制和保留不会给你一个保留计数为 1 的对象,它们会给你一个你拥有的对象,这就是你应该假设的。
init 影响保留计数的声明。这完全是假的。作为旁注,您在分配给cString 的作业中也缺少一个左大括号。
如果不是属性,只是在代码中声明,则需要显式保留或复制,即
NSString myString = [otherString copy];
或
NSString myString = [otherString retain];
无论哪种方式,您还需要确保它在某个时候发布。
【讨论】:
如果您不使用属性的 setter,例如 self.name = @"foo" 或 [self setName:@"foo"],而是直接分配变量,例如 name = @"foo",那么如何声明属性都无关紧要。
您必须了解,属性语法只是编写访问器方法的快捷方式(在本例中为-name 和-setName:)。如果您不调用这些方法(通过设置属性隐式调用),那么它们在内部的工作方式并不重要(这是您通过retain 或copy 指定的)。
【讨论】:
NSString * foo = @"bar";,那么您有一个NSString 对象@"bar",您可以使用名称foo 获得它。您可以将对象分配给其他变量:NSString * yak = foo;,这根本不会改变内存使用。它只是为同一对象提供了一个新名称。