NSString复制还是分配?你觉得幸运吗?

时间:2011-11-16 01:49:55

标签: objective-c c macos cocoa

我有一个线程,在开始之前需要来自GUI的信息。我最初错误地尝试做的是创建指向NSTextFields的指针,如下所示:

NSString *info = [gui_field stringValue];

//launch thread
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

当我尝试从线程中操作“info”时,这会导致问题。我认为是这种情况,因为从技术上讲,它仍然指向线程外的NSTextField的字符串表示。

这解决了问题:

NSString *info = [[gui_field stringValue] copy];

我认为这个副本(有自己的内存空间)根本不依赖于NSTextField。我还假设这应该是线程安全的。

这是适当的方法吗?我想我可以做到这一点:

NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];

两者产生的结果是否相同?在使用“copy”时我是否必须在字符串上显式调用release,或者默认情况下是否自动释放?

更新:或者,也许我只能发送一个指向该线程的指针,并使用“autorelease”复制该字符串,将其添加到该线程的自动释放池中:

NSString *info = [gui_field stringValue];

//launch thread
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *copied_str = [[info copy] autorelease];

    //do stuff

    [pool drain];
    //copied_str should now be history
}

这样,我不必担心显式释放copied_str。一旦线程结束,它就会消失。

2 个答案:

答案 0 :(得分:4)

无需依赖运气:)

alloc,copy,new和mutableCopy意味着你拥有了这个对象。这两个都会给你一个保留的对象。如果您正在管理内存,则需要将其释放。

按照惯例,其他方法会为您提供一个自动释放的对象。

例如,如果您想要一个自动释放的对象,可以调用:

NSString *str = [NSString stringWithString:yourString];

请参阅内存管理指南:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

特别是这里的四条规则:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

您拥有自己创建的任何对象

使用名称以“alloc”,“new”,“copy”或“mutableCopy”开头的方法(例如,alloc,newObject或mutableCopy)创建对象。

最后,两者都会复制字符串。

来自NSString docs的

<强> initWithString: 返回通过复制另一个给定字符串中的字符而初始化的NSString对象。

副本来自NSObject。它将副本定义为:

返回值 NSCopying协议方法copyWithZone:返回的对象,其中区域为nil。

NSString实现NSCopying协议,因此copy将返回字符串的副本。

有一个例外,即initWithString不复制字符串 - 如果传递字符串文字,它会将指针包装到常量并忽略retain / release。如果你很好奇,请看这里:Difference between NSString literals

答案 1 :(得分:2)

NSString *info = [[gui_field stringValue] copy];
NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];

那几乎完全相同。

[self performSelectorInBackground:@selector(myMethod:) withObject:info];

-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *copied_str = [[info copy] autorelease];

不,你不能这样做。即使访问GUI字符串对象只是为了复制它也足以导致崩溃。

我认为这种情况下,通常推荐的内存管理模式实际上并不能提供很好的解决方案,所以你可以走出它们。

NSString *info = [[gui_field stringValue] copy];

//launch thread
//pass ownership to callee
[self performSelectorInBackground:@selector(myMethod:) withObject:info];

// myMethod owns info!
-(void)myMethod:(NSString*)info
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [info autorelease];

另一个选项是将infoCopy保留为某处的实例变量。这将允许您使用正常的内存管理模式,但它不符合语义。它实际上不是一个实例变量,而是一个参数。

  

“我要求辩论。”

     

“这是滥用行为。”