我有一个线程,在开始之前需要来自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。一旦线程结束,它就会消失。
答案 0 :(得分:4)
无需依赖运气:)
alloc,copy,new和mutableCopy意味着你拥有了这个对象。这两个都会给你一个保留的对象。如果您正在管理内存,则需要将其释放。
按照惯例,其他方法会为您提供一个自动释放的对象。
例如,如果您想要一个自动释放的对象,可以调用:
NSString *str = [NSString stringWithString:yourString];
请参阅内存管理指南:
特别是这里的四条规则:
您拥有自己创建的任何对象
使用名称以“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保留为某处的实例变量。这将允许您使用正常的内存管理模式,但它不符合语义。它实际上不是一个实例变量,而是一个参数。
“我要求辩论。”
“这是滥用行为。”