2013-05-30 2 views
1

ли это лучшая практика, в инкубаторе, чтобы сохранить и освободить NSString следующим образом:Objective-C - NSMutableString SetString против NSString

-(void) setName:(NSString *)newName 
{ 
    if(newName != nil) 
    { 
     [newName retain]: 
     [m_Name release]; 
     m_Name = newName; //Where m_Name is a NSString * 
    } 
    //I'm not sure for this code, I have difficulties understanding memory-management in ObjC 
} 

Или изменить значение с помощью NSMutableString:

-(void) setName:(NSString *)newName 
{ 
    if(newName != nil) 
     [m_Name setString:newName]; //Where m_Name is a NSMutableString * 
} 

Если какой-либо или оба метода являются неправильными (-ами), дайте мне знать.

+3

Почему вы применяете свой собственный метод «сеттера»? Нет необходимости, если у вас нет другой обработки, кроме того, что вы разместили здесь. – rmaddy

+2

@maddy Я бы сказал, что OP работает из устаревшего учебника или книги. – bbum

ответ

3

Пара мыслей:

  1. Лучшая практика не писать сеттеры вообще, чтобы воспользоваться автоматически синтезированных методов доступа). Написание собственных - это только возможность испортить управление памятью или ввести ошибку. Перед тем, как вы напишете, у вас должна быть настоятельная потребность в настраиваемом сетевом устройстве.

  2. Возникающее соглашение, например, имена переменных, должно использовать имя свойства, которому предшествует ведущее подчеркивание (например, для свойства, называемого name, ivar - _name). Если вы опустите оператор @synthesize, компилятор, включенный в последние версии Xcode, сделает это автоматически для вас.

  3. Вопрос о том, что должен сделать сеттер, не имеет смысла, если вы не укажете, какие отличия в памяти у вашей собственности. Я собираюсь предположить, что вы определили свою собственность как retain.

  4. Изменение свойства на NSMutableString изменяет поведение вашего объекта, и я бы не советовал, если по какой-то причине вам действительно не нужна изменяемая строка.

  5. Ваш первый пример ничего не делает, если кто-то устанавливает свойство name на nil. Но если кто-то хочет установить его на nil, вы должны (а) освободить старое значение name; и (b) установите ваш ivar на nil. (Кстати, мой код ниже использует тот факт, что отправка сообщения объекту nil ничего не делает, поэтому мне не нужно проверять, является ли оно nil или нет, в этом случае.)

Таким образом, я предполагаю, что вы есть свойство, определяемое следующим образом:

@property (nonatomic, retain) NSString *name; 

и синтезировать линию, либо опущена или выглядит как:

@synthesize name = _name; 

Тогда, я думаю, установщик будет выглядеть так:

-(void) setName:(NSString *)name 
{ 
    // if you want to program defensively, you might want the following assert statement: 
    // 
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__); 

    if (name != _name) 
    { 
     [_name release]; 
     _name = name; 
     [_name retain]; 
    } 
} 

Кстати, я предполагаю, что ваш метод init правильно инициализирует _name и что dealloc освобождает его.

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     _name = nil; 
    } 
    return self; 
} 

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

Как bblum указывает, что это разумно использовать copy для NSString свойств:

@property (nonatomic, copy) NSString *name; 

Тогда, я думаю, что сеттер будет выглядеть следующим образом:

-(void) setName:(NSString *)name 
{ 
    // if you want to program defensively, you might want the following assert statement: 
    // 
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__); 

    if (name != _name) 
    { 
     [_name release]; 
     _name = [name copy]; 
    } 
} 

Но на самом деле, вы просто не должны писать сеттеры, если вам абсолютно не нужно.


И, наконец, ваш код содержит информацию о том, как найти управление памятью в замешательстве. В то время как вы, безусловно, необходимо, чтобы понять это, я хотел бы сделать два последних предложения:

  1. Рассматривают с помощью Automatic Reference Counting (ARC). Хотя это не избавляет от необходимости понимать, как работает управление памятью (см. Advanced Memory Management Programming Guide), упрощается запись кода, который правильно управляет памятью. Если вы пишете код ручной подсчета ссылок (MRC), очень легко сделать простые ошибки управления памятью, которые ARC позаботится о вас.

  2. Особенно, если вы собираетесь использовать MRC, воспользоваться себя статический анализатор Xcode (в «Анализ» в меню «Продукт» или нажмите сдвиг + команду + B). Это может облегчить поиск многих рутинных проблем управления памятью, которые поражают код MRC. Раздел Finding Memory Leaks руководства пользователя также показывает, как найти утечки при отладке вашего кода, но часто статический анализатор может идентифицировать проблемы, просто изучая ваш код.

+0

Декларации 'NSString'' @ property' всегда должны быть 'copy', а не' keep'. Это защита от 'foo.bar = someMutableString;'. Кроме того, * я думаю *, что ваша реализация сеттера закончится созданием двух уведомлений KVO в этом случае, потому что стандартный сеттер автоматически совместим с KVO. – bbum

+0

@bbum Согласовано в обоих пунктах, и я обновил свой ответ соответственно. – Rob

0

Первое решение лучше. Так обрабатываются свойства retain. Вы сохраняете новое значение, а затем отпустите старое значение. Также, если вопрос nil не имеет решающего значения для обработки, вы можете зависеть от реализации по умолчанию, созданной @synthesize.

Для второго решения это действительно не нужно, и это немного противоречит конвенции. Кроме того, в этом решении вам нужно инициализировать m_name, прежде чем присваивать ему любую строку. Вы можете сделать это в init.

- (void) init { 
    if (self = [super init]) { 
     m_name = [[NSMutableString alloc] init]; 
    } 
} 

Вывод: Первое решение, безусловно, лучше.

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