为NSString分配内存?

时间:2009-08-27 13:48:32

标签: objective-c cocoa memory

我是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
// ------------------------------------------------------------------------ **

4 个答案:

答案 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。使用属性(首选)

这是我首选的方法:实例变量的retaincopyassign然后由类处理。

正确声明属性,即:

@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.
}