Объективная разница C между self.variable и переменными присваиваниями

Боюсь, что я дурак.

Я потратил около трех часов на отслеживание утечки памяти, которая разрушала мое здравомыслие, и, прокомментировав половину своего приложения, я пришел к следующему выводу.

Учитывая следующее в нужных местах.

NSString *blah;

@property (nonatomic, retain) NSString *blah;

@synthesize blah;

-(id)initWithBlah:(NSString*)b {

     self.blah = b;    //this leaks
     blah = b;         //this does not

}

Я не особо разбираюсь в objectice c, я понимаю, что вне класса, если бы я вызывал object.blah = b; Я бы прозрачно вызвал функцию установки, которая сохранит b. Внутри функции, которую я предполагаю, установив ее с помощью self.blah = b, я по какой-то причине дважды сохраняю?

Может ли кто-нибудь объяснить мне, почему это так, а если нет, что я делаю неправильно?

Ваше здоровье


person dageshi    schedule 21.06.2010    source источник


Ответы (4)


blah = b

Изменяет переменную экземпляра класса напрямую.

self.blah = b

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

Вы должны добавить [blah release]; в свой метод dealloc, чтобы освободить ресурс, когда ваш класс будет выпущен.

person Paul Alexander    schedule 21.06.2010

Вы ошибаетесь. Присваивание blah = b; не имеет особого смысла, потому что после того, как ваш код вернется из initWithBlah:, вы больше не можете полагаться на существующую строку. Всякий раз, когда вы обращаетесь к нему в следующий раз, очень вероятно, что он уже был освобожден.

Присвоение self.blah = b; правильно, потому что оно вызывает установщик, и, таким образом, вы становитесь владельцем строки. Конечно, вы также должны выпустить blah в своем -dealloc, чтобы предотвратить утечку памяти.

person Ole Begemann    schedule 21.06.2010
comment
ааа спасибо. По какой-то причине я предположил, что, поскольку установщик прозрачно выполнял сохранение, какой-то фрагмент кода запомнил бы его существование и прозрачно освободил бы его для меня при уничтожении. Спасибо, что решает мою проблему. - person dageshi; 22.06.2010
comment
Между прочим, принято использовать @property (nonatomic, copy) вместо (nonatomic, retain) для NSString * переменных. При сохранении другой объект может назначить изменяемую строку вашему свойству, а затем позже изменить содержимое строки, чтобы ваш класс этого не заметил, что нарушит инкапсуляцию. - person Ole Begemann; 22.06.2010

Если вы даете только blah, он не выделяется для строки, если вы даете self.blah, он затем пытается инициировать self и выделяет для класса self и пытается выделить для переменной, к которой вы пытаетесь получить доступ, так что у вас есть чтобы освободить его, или сделайте blah = nil в методе dealloc.

i.e

- (void)dealloc 

{

     self.blah = nil;

      or

    [self.blah release];

}
person KSR    schedule 22.04.2013

Использование аксессуара - это нормально, если он протекает, значит, что-то еще не так.

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

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

YourObj *obj = [[YourObj alloc] initWithBlah:[NSString stringWithString:@"blah"]];

Хотя следующие утечки из-за передачи удерживаемой строки:

YourObj *obj = [[YourObj alloc] initWithBlah:[[NSString alloc] initWithString:@"blah"]];

Еще одна вещь, о которой вы должны знать, это то, что объявленные свойства не заботятся об очистке автоматически, поэтому не забудьте обработать это в -dealloc:

- (void)dealloc {
    self.blah = nil;
    // ...
}
person Georg Fritzsche    schedule 21.06.2010