iPhone: несколько ли объектов создают новые объекты, если назначены одному и тому же свойству? - PullRequest
1 голос
/ 08 марта 2011

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

У меня есть свойство:

@property (nonatomic, retain) AVAudioPlayer *audioPlayer;

Это затем синтезируется в моем файле viewcontroller.m.Теперь у меня есть метод для инициализации audioPlayer, установив URL для него и тому подобное.Меня беспокоит то, что я вызываю этот метод инициализации каждый раз, когда выбирается новый звук (чтобы позволить пользователю воспроизводить звук из средства выбора):

self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];

Приведенный выше код показывает строку, котораяВызывается каждый раз, когда изменяется значение средства выбора.

Прежде чем я буду слишком много болтать, выполняет ли приведенная выше строка а) создает НОВЫЙ экземпляр объекта AVAudioPlayer каждый раз, когда я вызываю его, или делает это б) просто «перезаписывает»"уже существующий экземпляр audioPlayer?Если а), я подозреваю, что мог бы убить память довольно быстро;что бы я сделал, чтобы сделать его эффективным?И если б), я думаю, это нормально, тогда?... и если секретный ответ в) (вы совершенно не понимаете, как создаются объекты), то, пожалуйста, пролите свет на мое невежество.

Спасибо!

Ответы [ 4 ]

3 голосов
/ 08 марта 2011
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];

должно быть либо:

self.audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil] autorelease];

или

AVAudioPlayer *aPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.audioPlayer = aPlayer;
[aPlayer release];

Некоторые детали добавлены для ясности.

Я думаю, что запутанная часть - это self.audioPlayer, верно? Это может помочь думать о нем как о методе, которым на самом деле является сеттер.

Эти строки эквивалентны:

self.audioPlayer = aPlayer;
[self setAudioPlayer:aPlayer];

И поскольку свойство установлено как «сохранить», метод setAudioPlayer имеет встроенную строку [aPlayer retain]. Поэтому, если вы не выпускаете локальную копию aPlayer, она сохраняется дважды.

Надеюсь, это поможет.

1 голос
/ 08 марта 2011

Это c)

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

@property (nonatomic, retain) AVAudioPlayer *audioPlayer;

, количество сохранений увеличивается до 2.

Когда вы назначаете другой объект для переменной аудиоплеера, чем старшеСчетчик сохранения экземпляра уменьшается на 1. Таким образом, старый объект будет просто утекать.

Вам понадобится

self.audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil] autorelease];

, если вы добавили вызов вызова аудиоплеера в свой метод dealloc.

1 голос
/ 08 марта 2011

Следует избегать использования свойств при назначении вновь выделенных объектов.Например, если ваше свойство audioPlayer синтезировано для чтения и записи в переменную-член с именем mAudioPlayer, то вам следует сделать следующее:

mAudioPlayer = [[AVAudioPlayer] alloc] initWithContentsOfURL:fileURL error:nil]

Если вам нужно использовать свойство (из-за побочных эффектов), тогда попробуйтеthis:

AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
self.audioPlayer = audioPlayer;
[audioPlayer release];

Это безопасно, потому что свойство автоматически сохраняет вновь созданный объект, чтобы вы могли впоследствии его освободить локально.Так что, если вы сделаете так, как вы упомянули, будет утечка.У вас будет ссылка 2 (1 из alloc и 1 из свойства, сохраняющего его).Если вы установите для self.audioPlayer значение 0 или другой экземпляр, его можно будет разблокировать только один раз.

Надеюсь, это поможет.

1 голос
/ 08 марта 2011

Каждый раз, когда вы вызываете alloc, создается новый экземпляр объекта. Однако ваше свойство с атрибутом «сохранить» примет ранее сохраненное значение и вызовет освобождение.

Так что для подсчета ссылок, alloc / init = +1 и release = -1. Что вам нужно сделать, так это беспокоиться о уменьшении последней копии, созданной, когда вы закончите с ней.

...