据我所知,任何init ...方法都会初始化一个新对象,而NSString stringWithString会将参数字符串的副本作为新对象。我也理解作为对象的所有者,我可以控制我分配的任何对象的释放/释放。我不明白的是什么时候我会使用stringWithString方法,因为任何以这种方式分配的局部变量都会让它的内存由NSString而不是本地类“拥有”。
Kochan编写的“Objective C中的编程”一书(第1版)使用以下代码(参见第342-344页)来解释initWithString比stringWithString更可取,因为AddressCard类将拥有名称变量contents。另外,使用stringWithString方法重复调用setName版本时,我没有任何错误。 TIA !!
//header file has appropriate declarations but not included here:
#import "AddressCard.h"
@implementation AddressCard;
-(NSString *) name
{
return name;
}
//Recommended code:
-(void) setName: (NSString *) theName
{
[name release]
name = [[NSString alloc] initWthString: theName];
}
//Incorrect code according to Kochan:
-(void) setName: (NSString *) theName
{
[name release]
name = [NSString stringWthString: theName];
}
//rest of class implementation code snipped
@end
答案 0 :(得分:27)
我不明白的是什么时候我会使用stringWithString方法,因为任何以这种方式分配的局部变量都会让它的内存由NSString而不是本地类“拥有”。
什么?否。
规则很简单:
alloc
,copy
,copyWithZone
或new
返回的任何对象的保留计数为1. retain
会增加接收对象的保留计数。release
会减少接收对象的保留计数。autorelease
告诉当前的自动释放池,以便稍后发送接收对象release
消息。stringWithString:
)都会返回一个代表您自动释放的对象。或者,消化了一下:
copy
,alloc
,retain
或new
的方法都会返回您拥有的对象。您显示的setName:
的错误实现是不正确的,因为它将一个自动释放的对象存储在实例变量中,当您意味着拥有该对象时。你应该保留它,或者在这种情况下,复制它。一种方法是简单地使用alloc
和initWithString:
,就像您展示的正确示例一样;另一种方式是copy
。
The Memory Management Programming Guide for Cocoa explains everything.每个Cocoa或Cocoa Touch程序员都应该不时阅读或重读。
答案 1 :(得分:6)
实际上,两位制定者都错了。由于一般的内存管理原因(其他地方已经很好地阐述),“错误的”错误。 “推荐”的错误有两个原因:
'正确'(恕我直言)方法是:
-(void) setName: (NSString *) theName
{
if (theName == name) return; // if they're equal, no need to do anything further
[name release];
name = [theName copy]; // sets name to nil if theName is nil
}
对于大多数对象,你实际上想要在第三行上获得而不是-copy,但对于字符串,复制几乎总是更好。
答案 2 :(得分:3)
initWithString和stringWithString之间的区别在于stringWithString返回一个自动释放的指针。这意味着您不需要专门发布它,因为下次自动发布池会清除任何自动释放的指针时会注意这一点。
另一方面,initWithString返回一个保留计数为1的指针 - 你需要在该指针上调用release,否则会导致内存泄漏。
请参阅https://stackoverflow.com/questions/193288/what-is-the-cost-of-using-autorelease-in-cocoa,了解为什么要使用自动发布与发布。
答案 3 :(得分:0)
在上面的错误代码中,在调用setName之后引用下一个时间名称,您将收到异常错误,因为该对象已被释放。您可以使用“更正”代码,或将stringWithString调用包装在显式保留调用中:
name = [[NSString stringWithString: theName] retain];
答案 4 :(得分:0)
我不明白的是什么时候我会使用stringWithString方法,因为任何以这种方式分配的局部变量都会让它的内存由NSString而不是本地类“拥有”。
使用stringWithString:
创建的字符串不属于NSString
,它由NSAutoreleasePool
拥有(尽管多个地方可以retain
一个对象,使所有权共享)。
对于stringWithString:
,当下一次处理自动释放池时(通常在应用程序的下一个事件循环期间),该字符串将变为无效,因为NSAutoreleasePool将release
其指针。如果您之前没有retain
字符串,那么您所拥有的任何指针(如果是您的类,则为name
)都将无效(变量name
仍然存在,但它将指向垃圾)。
自动释放很好,如果你不打算保留NSString
的任何指针,但由于你打算保留一个指针,你需要retain
NSString
。 initWithString:
会自动为您提供1的保留计数。