Выделение UIViewControllers в viewDidLoad. Было ли это ошибкой?

#ios #cocoa-touch #memory-management #uiviewcontroller #uikit

#iOS #cocoa-touch #управление памятью #uiviewcontroller #uikit

Вопрос:

Мы с коллегой разрабатывали наш код так, чтобы наши объекты контроллера представления выделялись в методе viewDidLoad наших объектов контроллера. Мы делали это много раз, и граф объектов, казалось, получался просто отлично. Через некоторое время мы обнаружили необходимость добавить еще один уровень над нашей текущей иерархией контроллеров представления, который будет владеть, выделять и освобождать наш предыдущий родительский контроллер представления.

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

Приведет ли это к массовым утечкам памяти? Или тот факт, что мы использовали сохраненные объявленные свойства, спасет нас, поскольку старые контроллеры будут освобождены автоматически? Существуют ли стили или соглашения, которые я должен рассмотреть? Спасибо за помощь!

Ответ №1:

Если вы создаете свои контроллеры просмотра в viewDidLoad, вы должны освободить их в viewDidUnload. Верно практически для любого объекта, а не только для контроллеров просмотра.

Но я не удивлюсь, если вы скажете «Wut !?» Если ваши контроллеры просмотра должны сохранять свое состояние с помощью предупреждений о памяти, то вы не хотите их выпускать. Но будет не лучше, если вы замените их новыми, которые имеют новое состояние.

Вероятно, не имеет смысла создавать контроллеры просмотра в viewDidLoad. Создайте их в initWithNibName:bundle: (и освободите их в dealloc). Шаблон проектирования заключается в том, что контроллеры представлений остаются, их представления могут появляться и исчезать. Если ваши подчиненные контроллеры представления имеют что-либо, требующее много памяти, отпустите только этот объект в их viewDidUnload. Затем при предупреждении о памяти вы все равно освободите много памяти, но все ваши контроллеры просмотра останутся в состоянии с низким потреблением памяти, Сохраняя только несколько флагов, списки индексов и т. Д., Которые им понадобятся для восстановления своих представлений по запросу.

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

1. Да, сохранение контроллеров, похоже, более тесно связано с MVC. Спасибо за совет 🙂

Ответ №2:

Если вы явно освобождаете каждый контроллер представления, который больше не нужен, вы не вызовете никаких утечек памяти. Обычно, когда вы представляете контроллер представления, объект, который выполняет представление, сохраняет контроллер для вас, поэтому вы можете освободить его, если вам больше не нужен доступ к нему. Но если вы используете UINavigationController и нажимаете новый контроллер представления, тогда вы должны реализовать метод viewDidUnload . Это прямо из документации Apple:

После загрузки в память представление контроллера представления остается в памяти до тех пор, пока не возникнет проблема нехватки памяти или сам контроллер представления не будет освобожден. В случае нехватки памяти поведение UIViewController по умолчанию заключается в освобождении объекта view, хранящегося в свойстве view, если это представление в данный момент не используется. Однако, если ваш пользовательский класс контроллера представления хранит выходы или указатели на какие-либо представления в иерархии представлений, вы также должны освободить эти ссылки при освобождении объекта представления верхнего уровня. Невыполнение этого требования предотвращает немедленное удаление этих объектов из памяти и потенциально может привести к утечке памяти позже, если вы впоследствии перезапишете любые указатели на них.

Есть два места, где ваш контроллер просмотра всегда должен очищать любые ссылки на объекты просмотра:

Метод dealloc Метод viewDidUnload Если вы используете объявленное свойство для хранения ссылки на ваше представление, и это свойство использует семантику сохранения, присвоения ему нулевого значения достаточно, чтобы освободить представление. Свойства, безусловно, являются предпочтительным способом управления вашими объектами просмотра из-за их удобства. Если вы не используете свойства, вы должны отправить сообщение о выпуске любому представлению, которое вы явно сохранили, прежде чем устанавливать соответствующее значение указателя равным нулю

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

1. Вы предлагаете мне освободить контроллеры просмотра в viewDidUnload?

2. Как именно вы представляете контроллеры просмотра? Вы пробовали реализовать UINavigationController или представить его модально?

3. Мы не используем UINavigationController. Мы вручную обрабатываем переключение вида.

4. Я понимаю. Вы могли бы просто освободить контроллер в своем viewDidUnload dealloc методе or, но это может привести к некоторым проблемам, основанным на том, как вы разработали свое приложение. Лучшим способом сделать это было бы просто создать пользовательский UIView и иметь основной UIViewController переключатель между этими представлениями. Затем вы можете просто освободить представления, которые в настоящее время не видны.

5. Я мог бы это сделать, но тогда вся функциональность контроллера будет перегружена в один класс, с которым становится сложно работать. Спасибо за ответ!