2009-08-27 3 views
2

Я новичок в Objective-C, и мне немного любопытно, как я должен управлять памятью для локальных переменных NSString, приведенных ниже, и связанных переменных экземпляра внутри объекта класса. Код, который у меня есть, отлично работает, но просто любопытно, что касается лучшей практики.Выделение памяти для 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 
// ------------------------------------------------------------------------ ** 

ответ

8

Прочитать memory management rules. 9 простых абзацев, которые объясняют все, что вам нужно знать.

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

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

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

- (void)setGeekName:(NSString*)gName { 
    if (geekName != gName) { 
     [geekName release]; 
     geekName = [gName copy]; 
} 

Вам также нужны dealloc процедуры, которые релизы geekName:

- (void) dealloc 
{ 
    [geekName release]; 
    [super dealloc]; 
} 

В качестве альтернативы, вы можете использовать Объективные свойства C.Вместо того, чтобы ваш интерфейс с указанием:

- (NSString*) geekName; 
- (void) setGeekName:(NSString*)gName; 

Используйте свойство:

@property (nonatomic, copy) NSString* geekName; 

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

@synthesize geekName; 

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

2

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

Вы должны только беспокоиться об освобождении члена «geekName» в dealloc() для класса он находится.

+0

Я вижу, мой класс интерфейс, как показано ниже, так что ваше высказывание я должен действительно иметь метод dealloc для класса, который делает а [geekName релиз], я думал, что это мог бы быть освобожден, когда я выпустил объект planetClass (т.е. [newPlanet_01 релиз];) @interface planetClass: NSObject { \t поплавок силы тяжести; \t поплавок масса; \t символ * имя ; \t NSString * geekName; \t } Cheers gary – fuzzygoat

+0

@fuzzygoat - зависит от того, как вы выделили эту строку изначально. Если вы использовали alloc() или что-то подобное, вам нужно его освободить. Если вы назначили его из статической «цитируемой строки», ее не нужно выпускать. –

0

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

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

0

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

Как вы читаете код, вы устанавливаете локальные переменные указателям, возвращаемым двумя объектами класса. Если вы правильно написали классы newPlanet*, тогда объекты строк должны быть освобождены при отпускании классов. Если же ваши две локальные переменные пытаются использовать указатели, вы будете иметь проблемы, как объекты больше не Ther

Два возможных поправок:

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

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

Edit - примечание, так как дополнительные детали класса показало

В вашем 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

Привет, Abizern, я просто урезал код (его только ранние учебные материалы) и разместил его целиком выше. Я просто читаю ваш ответ прямо сейчас, большое спасибо. – fuzzygoat

+0

Я только что начал (на прошлой неделе, если быть точным), я знаю о @synthesize и свойствах, но до сих пор не понял, насколько они выглядят, я думаю, что они в главе 9, я все еще на 3 :) – fuzzygoat

+0

Это нормально; помните об этом, когда вы доберетесь до этой части. – Abizern

Смежные вопросы