Переход к корневому контроллеру представления без сбоя анимации для табличного представления - PullRequest
12 голосов
/ 31 марта 2011

У меня есть 3 вида контроллера в панели вкладок контроллера. При нажатии на любую вкладку загружается его корневой контроллер представления в стеке навигации.

например. tab1, tab2 и tab3.
Контроллер второго представления в стеке навигации (tab2VC2) имеет tableView. Нажмите на tab2, покажите VC на tab2, затем нажмите на tab1, попытайтесь перейти к его rootVC. Затем приложение вылетает со словами

[UserDetailVC Tableview: cellForRowAtIndexPath]: сообщение отправлено на освобожденный экземпляр 0xe0a23b0

Если я popToRootVC с анимацией, тогда все в порядке. Я обнаружил, что viewDidAppear во вкладке tab2VC2 вызывается там, где вызывается tableView.reloadData, затем dealloac, кажется, в то время как reloadData начинает работать, таблица освобождается. в случае анимации это занимает некоторое время, поэтому оно не падает. Но без анимации происходит сбой. Как вы думаете, это ошибка iPhone? или я делаю не так? Поскольку в поп-контроллере есть опция без анимации, она должна работать, не так ли?

#pragma mark Tab bar controller delegate
- (void)tabBarController:(UITabBarController *)tbController didSelectViewController:(UIViewController *)viewController {
    int i = tbController.selectedIndex;
    NSArray *mycontrollers = tbController.viewControllers;
    [[mycontrollers objectAtIndex:i] popToRootViewControllerAnimated:NO];
}

Ответы [ 6 ]

36 голосов
/ 26 июля 2011

Я считаю это ошибкой или, по крайней мере, слабостью в UIKit, но я уже потратил на это половину своего дня, поэтому я не собираюсь писать это с примером кода и сообщать об этом прямо сейчас Apple. Если кто-то еще захочет это сделать, я буду признателен.

Вот что я думаю, что происходит под капотом. У вас есть UITableViewController, назовем его myTable, в стеке UINavigationController, и этот стек навигации скрыт, потому что он находится на невыбранной вкладке или чем-то еще. Затем вы вызываете [myTable.tableView reloadData], и iOS ловко оптимизирует, не перезагружая данные сразу, потому что пользователь все равно не увидит их, если они находятся на скрытой вкладке. Вместо этого запрос на перезагрузку откладывается и сохраняется где-то для отображения представления. Но прежде чем это можно будет показать, вы вытаскиваете myTable из стека навигации. Когда отображается исходная вкладка myTable, выполняется запрос на перезагрузку, но его источника данных больше нет, поэтому это неверный доступ.

Теперь из моих тестов с подклассом UITableViewController, который использует автоматически предоставленное свойство tableView (не загружается из файла NIB), UITableView не освобождается при освобождении myTable, как в ситуации выше. Это было бы хорошо, за исключением того, что реализация по умолчанию для dealloc для UITableViewController не очищает свойство dataSource для UITableView (которое было установлено реализацией init по умолчанию).

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

- (void)dealloc {
  ...
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
  [super dealloc];
}

Любая дополнительная мудрость будет приветствоваться.

4 голосов
/ 10 июля 2012

Ответ Джесси работает отлично.Я только что сделал небольшую модификацию для ARC Support

- (void)dealloc 
{
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
}
0 голосов
/ 29 февраля 2012

Хотя ответ Джесси обеспечил понимание семантики вокруг этой проблемы, в моем случае основная причина была другой.Просто подумал, что упомяну это, если кто-то окажется в такой же ситуации.

Я видел сообщение об ошибке

* - [UIAnimator removeAnimationsForTarget:]: сообщение отправлено на освобожденный экземпляр ...

, где рассматриваемый объект был UITableViewCell.При проверке в моем коде не было проблем с выделением памяти.

Проблема оказалась в том, что я вызывал один из методов семейства popViewController:animated: из потока, не являющегося пользовательским интерфейсом.Этот поток был создан для запуска некоторых сетевых операций и задач обработки базы данных.Я просто переместил вызов метода pop в поток пользовательского интерфейса и обнаружил, что перестал получать сообщение об ошибке.

0 голосов
/ 19 февраля 2012

У меня была похожая проблема, и я уверен, что это как-то связано с новым SDK, если честно. Следующий код работал нормально раньше. У меня есть один навигационный контроллер и новый, добавленный к нему с тремя различными представлениями, которые помещаются на него (Подумайте: смена пароля, когда у вас есть 3 различных шага: контроль, изменение, повтор.) Если пользователь введет неправильный пароль, вы сначала нажмите на кнопку «Изменение пароля контроллера», а затем нажмите на первую страницу (выход из системы).

Это работало раньше:

-(void)logout {
    [self.presentedViewController dismissModalViewControllerAnimated:TRUE];

    self.localNavigationController = nil;

    [self.navigationController popToRootViewControllerAnimated:TRUE];
 }

Чтобы решить эту проблему, измените ViewWillAppear на ViewDIDAppear. Вы можете иметь некоторую задержку, но, по крайней мере, она не вылетает:)

0 голосов
/ 08 июля 2011

Вы можете попробовать это, чтобы избежать проблемы:

-(void)viewWillAppear:(BOOL)animated
{
   if (animated)
   {
      [self.tableView reloadData];
   }
}

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

0 голосов
/ 31 марта 2011

Дважды щелкните свой исполняемый файл в списке групп и файлов; щелкните вкладку «Аргументы»; нажмите «+» в нижней панели, введите «NSZombieEnabled», установите значение «YES», установите флажок, нажмите красную точку, чтобы закрыть. Теперь снова запустите ваш тестовый пример, и он скажет вам, какой объект был освобожден. Я подозреваю, что это массив, поддерживающий ваш tableView в tab2V2. Убедитесь в правильности обработки памяти (правильно ли она сохраняется и освобождается?).

...