Выделение памяти для NSString? - PullRequest
2 голосов
/ 27 августа 2009

Я новичок в Objective-C , и мне немного любопытно, как мне следует управлять памятью для локальных переменных NSString, показанных ниже, и связанных переменных экземпляра внутри объекта класса. Код, который у меня есть, работает нормально, но просто любопытно, как лучше всего практиковаться.

Отредактировано, чтобы включить полный код, ничего особенного, как я говорю, мне просто любопытно, если в этом контексте я должен делать alloc / release для объектов NSString.

// 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 ]

8 голосов
/ 27 августа 2009

Прочитайте правила управления памятью . 9 простых параграфов, объясняющих все, что вам нужно знать.

Поскольку geekName не начинается с «alloc» или «new» или содержит «copy», он должен возвращать строку, которой вы «не владеете». Таким образом, вам не нужно (и, действительно, не нужно) выпускать его, и вы также не должны хранить ссылку на него. Вы можете вернуть его из метода, в котором вы находитесь, и в этом случае имя вашего метода также не должно начинаться с «alloc» или «new» или содержать «copy».

Если вы хотите сохранить его, вы должны вступить во владение им, позвонив в службу сохранения, или потому что это строка NSString, лучше копировать. Это может быть автоматическим, если вы назначите его для свойства копирования / сохранения.

В коде, который вы сейчас разместили, вы допустили ошибку в своем установщике. Ваш установщик должен получить копию входного параметра, что-то вроде:

- (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;

И вместо вашей реализации сеттеров и геттеров, пусть система синтезирует их для вас:

@synthesize geekName;

Вам все еще нужен метод dealloc для освобождения geekName.

2 голосов
/ 27 августа 2009

Это будет зависеть от того, как настроено свойство для «geekName». Я предполагаю, что он просто возвращает ссылку на существующий член в классе, а не создает копию? Если это так, вам не нужно беспокоиться о выпуске чего-либо в коде, который у вас есть.

Вам следует беспокоиться только об освобождении члена "geekName" в dealloc () для класса, в котором он находится.

0 голосов
/ 27 августа 2009

В зависимости от того, как вы используете две локальные переменные, вам может потребоваться дополнительное управление памятью.

При чтении кода вы устанавливаете локальные переменные для указателей, возвращаемых двумя объектами класса. Если вы написали классы 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.
}
0 голосов
/ 27 августа 2009

Переменные свободны. Локальные переменные выделяются для вас компилятором; переменные экземпляра выделяются средой выполнения как часть экземпляра.

Объекты, чьи указатели вы помещаете в переменные, не являются свободными; вам может понадобиться отпустить их. Нужно ли вам освобождать объект или нет, определяется правилами .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...