我是Objective-C的新手,我对如何管理下面显示的本地NSString变量以及类对象中的关联实例变量有点好奇。我的代码工作正常,但对最佳实践感到好奇。
编辑包含完整的代码,没什么特别的,就像我说我只是好奇,如果在这个上下文中我应该在NSString对象上进行alloc / release。
// MAIN ------------------------------------------------------------------- **
#import <Foundation/Foundation.h>
#import "PlanetClass.h";
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *planet_01_Geek;
NSString *planet_02_Geek;
// Create planets
PlanetClass *newPlanet_01 = [[PlanetClass alloc] init];
[newPlanet_01 setGeekName:@"StarWars"];
PlanetClass *newPlanet_02 = [[PlanetClass alloc] init];
[newPlanet_02 setGeekName:@"Dune"];
// Query a planet
planet_01_Geek = [newPlanet_01 geekName];
planet_02_Geek = [newPlanet_02 geekName];
// Print details
NSLog(@"Planet Geek = %@", planet_01_Geek);
NSLog(@"Planet Geek = %@", planet_02_Geek);
// Clean up
[newPlanet_01 release];
[newPlanet_02 release];
[pool drain];
return 0;
}
...
// CLASS HEADER ----------------------------------------------------------- **
#import <Foundation/Foundation.h>
@interface PlanetClass : NSObject {
NSString *geekName;
}
- (NSString*) geekName;
- (void) setGeekName:(NSString*)gName;
@end
// ------------------------------------------------------------------------ **
...
// CLASS BODY ------------------------------------------------------------- **
#import "PlanetClass.h"
@implementation PlanetClass
- (NSString*)geekName {
return geekName;
}
- (void)setGeekName:(NSString*)gName {
geekName = gName;
}
@end
// ------------------------------------------------------------------------ **
答案 0 :(得分:8)
阅读memory management rules。 9个简单的段落,解释了你需要知道的一切。
因为geekName不以“alloc”或“new”开头或包含“copy”,所以它应该返回一个你不“拥有”的字符串。因此,您不需要(实际上也不必)释放它,也不能存储对它的引用。您可以从您所在的方法返回它,在这种情况下,您的方法名称也不应以“alloc”或“new”开头或包含“copy”。
如果您希望保留它,您必须通过调用retain来获取它的所有权,或者因为它的NSString,更好的是复制。如果将其分配给复制/保留属性,则可能是自动的。
在您现在发布的代码中,您在setter中出错了。你的setter应该带一个输入参数的副本,如:
- (void)setGeekName:(NSString*)gName {
if ( geekName != gName ) {
[geekName release];
geekName = [gName copy];
}
然后你还需要一个dealloc例程来释放geekName:
- (void) dealloc
{
[geekName release];
[super dealloc];
}
或者,您可以使用Objective C属性。而不是您的界面显示:
- (NSString*) geekName;
- (void) setGeekName:(NSString*)gName;
使用属性:
@property (nonatomic, copy) NSString* geekName;
而不是你的setter和getter的实现,让系统为你合成它们:
@synthesize geekName;
你仍然需要dealloc方法来释放geekName。
答案 1 :(得分:2)
这取决于你如何设置“geekName”的属性。我会假设它只返回对类中现有成员的引用而不是创建副本?如果是这种情况,您不必担心在那里的代码中发布任何内容。
你应该只需要担心在dealloc()中为它所在的类释放“geekName”成员。
答案 2 :(得分:0)
变量是免费的。编译器为您分配局部变量;实例变量由运行时分配为实例的一部分。
您在变量中放入指针的对象不是空闲的;你可能需要释放它们。是否需要释放对象由the rules确定。
答案 3 :(得分:0)
根据您使用两个局部变量的方式,您可能需要更多内存管理。
您的代码读取方式,您将局部变量设置为两个类对象返回的指针。如果您已正确编写newPlanet*
类,则应在释放类时释放字符串对象。如果你的两个局部变量然后尝试使用指针,那么你会遇到问题,因为对象不再是
两种可能的更正:
<强> 1。明确保留字符串
由于直接分配局部变量,您应该明确地保留对象:
planet_01_Geek = [[newPlanet_01 geekName] copy];
planet_02_Geek = [[newPlanet_02 geekName] copy];
我在这里指定副本,因为这是保持可能可变的对象的首选方式,否则如果原始更改,则局部变量也将更改。
<强> 2。使用属性(首选)
这是我首选的方法:实例变量的retain
,copy
或assign
然后由类处理。
正确声明属性,即:
@property (nonatomic, copy) NSString *planet_01_Geek;
@property (nonatomic, copy) NSString *planet_02_Geek;
在实施中使用@synthesize
。
然后使用属性语法分配变量。
self.planet_01_Geek = [newPlanet_01 geekName];
self.planet_02_Geek = [newPlanet_02 geekName];
这样,正确的内存管理规则将适用于赋值,而合成的访问器方法也将负责释放当前分配给局部变量的任何对象。
编辑 - 显示更多课程详细信息后的注释
在你的setGeekName:
方法中,你正在泄漏记忆。当您为局部变量分配新指针时,您不会向以前在该对象中的对象发送释放。更好的方法(使用retain
而不是copy
来保持简单:
- (void)setGeekName:(NSString *)gName {
[gName retain]; // Hold on to the object that is passed in.
[geekname release]; // Let go of your current object.
geekName = gName; // Now allocate the new object.
}