Простой вопрос памяти Objective-C — освобождение свойства, не удается перераспределить и инициализировать

#iphone #objective-c

#iPhone #objective-c

Вопрос:

Я использую эту ветку AudioStreamer для потоковой передачи аудио.

В контроллере представления у меня есть AudioStreamer в качестве свойства: @property (nonatomic, retain) AudioStreamer *streamer

Когда загружается контроллер представления, я запускаю поток, подобный этому:

self.streamer = [[AudioStreamer alloc] initWithURL:[NSURL URLWithString:preset.url]];

И чтобы остановить поток, освободить его и запустить новый поток, я делаю это:

 [streamer stop];
[streamer release];
self.streamer = nil;
self.streamer = [[AudioStreamer alloc] initWithURL:[NSURL URLWithString:preset.url]];
  

Это не работает, потому что в initWithURL: методе есть проверка для просмотра if (self != nil) и эта проверка завершается неудачей.

Кто-нибудь сможет пояснить, почему это не работает?

Спасибо.

РЕДАКТИРОВАТЬ: на самом деле некоторые проблемы с моим проектом вызывали странные проблемы. Тем не менее, я пометил ответ как правильный, потому что в нем было несколько полезных советов по памяти, которые также помогли.

Комментарии:

1. можете ли вы показать нам код метода initWithURL?

2. Какие симптомы заставляют вас полагать, что проблема связана с initWithURL: вызовом? В этом методе нет ничего необычного, и AudioStreamer он супер NSObject , так что маловероятно, что [super init] произойдет сбой.

3. Я бегло взглянул на класс AudioStreamer, если инициализатор в вашем fork тот же, то я на самом деле не знаю, почему он терпит неудачу, класс просто наследуется от NSObject, а initWithURL вообще ничего особенного не делает.

Ответ №1:

Вы переопределяете экземпляр streamer, задавая для него синтаксис dot и используя alloc.

Синтезированный установщик сохранит его один раз и выделит во второй раз, вам следует добавить автоматическое освобождение:

 self.streamer = [[[AudioStreamer alloc] initWithURL:[NSURL URLWithString:preset.url]] autorelease];
  

Эта строка:

 self.streamer = [[AudioStreamer alloc] initWithURL:[NSURL URLWithString:preset.url]];
  

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

 [streamer release];
self.streamer = nil;
  

перед этим.

Однако вы должны сделать

 [streamer release];
  

в вашем методе освобождения.

Комментарии:

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

Ответ №2:

Прежде всего, вы дважды освобождаете streamer , не намереваясь этого делать.

 [streamer release];     // Releases the ivar, but doesn't set it to nil.
self.streamer = nil;    // This is a property access, which releases the old
                        // value (again) before setting to nil.
  

И ваше назначение в последней строке приводит к утечке ссылки (вы выделяете, а затем присваиваете retain свойству).

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

 [self.streamer stop];
self.streamer = [[[AudioStreamer alloc] initWithURL:[NSURL URLWithString:preset.url]] autorelease];
  

Все сказанное, неудачная self != nil проверка не обязательно объясняется этим, но это может быть, в зависимости от того, что AudioStreamer делает для своего внутреннего управления объектами.