Представляет ли UIViewControllerModalViewController: анимированный: сохранить модальный контроллер?

Это влияет на то, как я взаимодействую с моими модальными контроллерами. Когда я впервые начал работать в iOS, я предположил, что UIViewController не сохранил представленный в модальном представлении вид. Ну, на самом деле это было больше похоже на то, что у меня не было причин предполагать, что он их сохранил. Это оставило меня с довольно неудобными попытками освободить их, когда я понял, что они закончили анимацию увольнения:

_myViewController = [[UIViewController alloc] init];
[self. present modalViewController:_myViewController animated:YES];
/* 
Some stuff, then in a different method all together,
probably as the result of a delegate callback or something...
*/
[self dismissModalViewControllerAnimiated:YES];
[_myViewController performSelector:@selector(release) withObject:nil afterDelay:0.5f];

Затем я увидел свойство modalViewController UIViewController и подумал: "Человек, я надеюсь, что он сохранит это свойство, когда будет представлен контроллер модального представления". Разумеется, я зарегистрировал счет удержания на несколько из этих попыток и заметил общее увеличение сразу после вызова presentModalViewController:animated: (я знаю, что количество отсчетов не является идеальной метрикой). Итак, где-то вдоль линии, я начал использовать гораздо более приятный образец, где я предполагаю, что любой объект контроллера, который я представляю в виде модальности, сохраняется контроллером представления. Это позволяет мне написать стандартный код:

UIViewController* myViewController = [[UIViewController alloc] init];
[self presentModalViewController:myViewController animated:YES];
[myViewController release]; // <- Fire and forget!

Теперь, конечно, нет никакой неловкости: нет необходимости ждать окончания анимации или даже хранить ссылку на представленный контроллер, если мне это не нужно. Я могу вслепую уволить его позже и не беспокоиться о утечке. Мне это нравится.

Я зарегистрировал много dealloc в моих модально представленных контроллерах, и они всегда называются именно тогда, когда я хочу, что заставляет меня чувствовать себя уверенно в моем подходе: UIViewController presentModalViewController:animated: сохраняет представленный контроллер как свойство modalViewController.

Но, и это мясо этого вопроса, я понял, что не могу подтвердить это как документированное поведение. И если это не задокументировано, я не должен чувствовать себя так же безопасно, как и я, потому что Apple не делает promises о долговечности недокументированного поведения. Свойство modalViewController общедоступно readonly, поэтому я могу предположить только сохранение за кулисами, а только документация на presentModalViewController:animated: говорит только:

Устанавливает свойство modalViewController указанному контроллеру представления.

"Наборы" может быть assign или retain. Ничто, что я читаю, невольно подтверждает или отрицает мою позицию. Поскольку это предположение я часто делаю, мне бы очень понравилось, если бы кто-то мог указать на факт, что я пропустил где-то в недрах документации, чтобы успокоить мой разум в отношении законности этой практики.

EDIT: В отливе и потоке повседневной жизни в SDK iOS я оказался в заголовке для UIViewController и начал читать некоторые из них. Я почерпнул какую-то полезную информацию, которая напомнила мне об этом вопросе, и я решил опубликовать ее, если какой-то будущий пользователь наткнется на этот вопрос и захочет как можно больше информации удовлетворить свою паранойю очень стандартной практики. Маленький кусок просто это, из блока ivar интерфейса @interface в UIViewController.h:

UIViewController *_childModalViewController;

В отличие от этих других объявлений:

UIViewController *_parentViewController; // Nonretained
NSHashTable      *_childViewControllers; // Nonretained

В комментариях явно указано, что не сохраняется. В силу отсутствия комментариев к заявке на идентификатор модуля modal view, казалось бы, он сохраняется.

Ответ 1

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

Итак, в этом случае вы должны просто передать контроллер вида на presentModalViewController:animated:, а затем отпустить его (или использовать автозапуск).

Это применимо везде в Objective-C. Если объект принимает другой объект в качестве метода ввода, вам никогда не придется сохранять этот объект от его имени.

Как указано в комментариях, если вы читаете документацию Apple по управлению памятью, вы найдете в разделе "Слабые ссылки" , в котором говорится:

Важно. В Cocoa ссылки на источники данных таблицы, схематический вид пунктов, наблюдателей уведомлений и делегаты считаются слабыми (для Например, объект NSTableView делает не сохранять свой источник данных и Объект NSApplication не сохраняется его делегата). Только документация описывает исключения из этого условность.

Это фактически говорит о том, что это само по себе соглашение и что исключения будут указаны в документации, однако, перейдя к документации для NSTableView и рассмотрев метод setDataSource:, мы видим:

Обсуждение В управляемой памяти окружающей среды, приемник поддерживает слабая ссылка на источник данных (то есть он не сохраняет данные источник, см. Связь с Объекты). После установки данных source, этот метод вызывает фрагмент.

Этот метод повышает NSInternalInconsistencyException, если anObject не отвечает ни на numberOfRowsInTableView: или Tableview: objectValueForTableColumn: ряд:.

Ответ 2

Хороший вопрос! Я не совсем уверен в ваших предположениях. Соответствующее свойство определено в документах как:

@property(nonatomic, readonly) UIViewController *modalViewController

Как вы указываете, он не указывает, как он хранится.

Этот документ: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html

фактически указывает, что если сохранение/назначение/копия не указано, это назначение является поведением по умолчанию.


Я также прочитал ответ d11wtq, но не уверен, что полностью согласен. Я согласен с соглашениями об управлении памятью obj-c, но есть много случаев, когда методы инфраструктуры не сохраняют свойства (считайте слабые ссылки, делегаты и т.д.). Надеюсь, кто-то может подтвердить ваши предположения.

Ответ 3

уверен, что он задокументирован. И, кстати, я не знаю другого пути: D Я использую метод alloc-present-release, так как я начал программирование iOS 1,5 года назад

Вы можете найти пример кода, если вы запустите XCode и создадите "служебное приложение". В коде (Apple) код должен быть:

FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil];
controller.delegate = self;

controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];

[controller release];

Ответ 4

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

Кстати, часть причин, по которым печать keepCount не является хорошей стратегией отладки, заключается в том, что там, где вы устанавливаете NSLog или точку останова, может оказаться не подходящим местом для просмотра счета сохранения. Некоторое сохранение или освобождение может следовать после того, как вы проверите его количество удержаний, вызванное интересующим вас событием.

Итак, если вы действительно хотите знать, что будет отсчет удержания с момента события, просто переопределите - (id) release и - (void) метод выпуска и распечатайте там журналы, и считайте сами. Разумеется, вы должны называть superclass сохранение/освобождение в конце ваших методов. Таким образом, например, вы можете получить очень четкий ответ на свой первоначальный вопрос.

Ответ 5

если вы выполняете анимацию , представляя контроллер модального представления, например

[viewController presentViewController:modalViewController animated:YES completion:^{
    NSLog(@"presentViewController completion");
}];
/*DONT RELEASE IF THERE IS ANIMATION*/
//[modalViewController release];

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

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

   [viewController presentViewController:modalViewController animated:NO completion:^{
    NSLog(@"presentViewController completion");
}];

[modalViewController release];/*YOU MAY RELEASE MODALVIEW CONTROLLER IMMEDIATELY*/