IOS: непредвиденное поведение popViewController
Я искал интернет для решения. Я ничего не смог найти.
Так:
Я использую UINavigationController. Я нажимаю на него два UIViewControllers. Во втором нажатом ViewController я выполняю этот код:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
NSLog([error localizedDescription]);
[self.navigationController popViewControllerAnimated:YES]; }
Ожидаемое, что произойдет, будет то, что последний нажатый ViewController исчезнет. В этом приложении я делаю это на нескольких местах, и он отлично работает везде, ожидаемый в этом самом ViewController.
Случается, что только задняя кнопка отключается от экрана (анимированная), но все остальное остается на экране. На выходе Console две строки распечатываются после выполнения этой строки:
2011-03-14 16: 32: 44,580 TheAppXY [18518: 207] вложенный pop анимация может привести к повреждению панель навигации
2011-03-14 16: 32: 53.507 TheAppXY [18518: 207] Завершение переход в неожиданный государство. Дерево навигации навигации панели навигации может быть поврежден.
Два сообщения об ошибках, на которые я не мог найти ЛЮБОЙ информации.
Я использую XCode 4 и iOS SDK 4.3. Может быть, кто-нибудь может помочь мне с этой проблемой.
Ответы
Ответ 1
Я столкнулся с аналогичной ситуацией в своем коде, и в сообщении говорилось:
Вложенная анимация push может привести к повреждению панели навигации
Завершение перехода навигации в неожиданном состоянии. Дерево видимости панели навигации > может быть повреждено.
Мое обнаружение этой проблемы состояло в том, что я несколько раз нажимал на два контроллера представления один за другим, и оба были анимированы.
В вашем случае кажется, что вы можете несколько раз отображать несколько контроллеров представлений с анимацией.
Следовательно, пока одно представление проходит анимацию, вы не должны запускать анимацию на другом представлении.
Я также обнаружил, что если я отключил анимацию на одном представлении, сообщение об ошибке исчезло.
В моем случае это была проблема с логикой потока, поскольку я не собирался нажимать два контроллера просмотра один за другим. Один из них был вставлен в логику коммутатора, а другой - после его окончания.
Надеюсь, это поможет кому-то.
Ответ 2
Вы можете получить это в любое время, которое вы пытаетесь выполнить перед viewDidAppear
. Если вы установите флаг, то просто проверьте этот флаг в viewDidAppear
, у вас не будет проблемы.
Ответ 3
Я создал замену для UINavigationController, которая будет останавливать анимацию для вас и полностью исключить эту проблему.
Возьмите его из BufferedNavigationController
Ответ 4
У меня тоже была эта проблема, и вот то, что вызывало мое:
- В RootViewController я использую несколько объектов UISegmentedControl, чтобы определить, какой из многих видов для загрузки следующий.
- В этом (суб/2-м) представлении я нажал (с помощью кнопки "Назад" ) обратно в RootViewController.
- В RootViewController я обрабатывал viewWillAppear для "reset" каждого из моих объектов UISegmentedControl для selectedSegmentIndex -1 (что означает, что сегмент не выглядит "нажатым" ).
- То, что "reset" вызвало каждый из моих объектов UISegmentedControl, чтобы запустить их связанные (и отдельные) IBActions.
- Поскольку я не обрабатывал "выбор" из -1, у меня одновременно срабатывало несколько методов, все пытались нажать другое представление.
Мое исправление? Я затянул мои инструкции if... then и выполнил выполнение какого-либо кода в UISegmentedControl IBActions при выбореSegmentIndex == -1.
Я все еще не уверен, почему у меня возникли ошибки "поп-анимации", а не "push", но, по крайней мере, выяснил мою ошибку и исправил ее!
Надеюсь, это поможет кому-то еще!
Ответ 5
Да, к сожалению, яблоко не синхронизировало анимацию UINavigationController. Решение Andrew отлично, но если вы не хотите покрывать всю свою функциональность, есть более простое решение, переопределите эти два метода:
// navigation end event
- ( void ) navigationController : ( UINavigationController* ) pNavigationController
didShowViewController : ( UIViewController* ) pController
animated : ( BOOL ) pAnimated
{
if ( [ waitingList count ] > 0 ) [ waitingList removeObjectAtIndex : 0 ];
if ( [ waitingList count ] > 0 ) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ];
}
- ( void ) pushViewController : ( UIViewController* ) pController
animated : ( BOOL ) pAnimated
{
[ waitingList addObject : pController ];
if ( [ waitingList count ] == 1 ) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ];
}
и создайте переменную экземпляра NSMutableArray, называемую waitList, и вы закончите.
Ответ 6
Эта проблема возникает со мной, когда я использую раскадровки. Я допустил ошибку:
У меня есть UIButton с действием для выполнения SegueWithIdentifier. Поэтому я связываю push-сегу с Button с другим ViewController, поэтому возникает эта проблема.
Чтобы решить:
Свяжите действие кнопки в UIButton и соедините push-сег между двумя ViewControllers.
Ответ 7
Объединяя ответы Милгра и Эндрю, я дал мне то, что работает надежно и является более простой заменой замены UINavigationController.
Это улучшает ответ Милгра, чтобы заставить его работать с толчками и попками, но проще, чем Andrew BufferedNavigationController. (Используя BufferedNavigationController, я иногда получал переходы, которые никогда не будут завершены, и будет показывать только черный экран.)
Вся эта вещь, кажется, не нужна на iOS8, но мне все еще нужно было на iOS7.
@implementation UINavigationControllerWithQueue {
NSMutableArray *waitingList;
}
-(void) viewDidLoad {
[super viewDidLoad];
self.delegate = self; // NOTE: delegate must be self!
waitingList = [[NSMutableArray alloc] init];
}
# pragma mark - Overrides
-(void) pushViewController: (UIViewController*) controller
animated: (BOOL) animated {
[self queueTransition:^{ [super pushViewController:controller animated:animated]; }];
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
UIViewController *result = [self.viewControllers lastObject];
[self queueTransition:^{ [super popViewControllerAnimated:animated]; }];
return result;
}
- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated {
NSArray* results = [self.viewControllers copy];
[self queueTransition:^{ [super popToRootViewControllerAnimated:animated]; }];
return results;
}
# pragma mark - UINavigationControllerDelegate
-(void) navigationController: (UINavigationController*) navigationController
didShowViewController: (UIViewController*) controller
animated: (BOOL) animated {
[self dequeTransition];
}
# pragma mark - Private Methods
-(void) queueTransition:(void (^)()) transition {
[waitingList addObject:transition];
if (waitingList.count == 1) {
transition();
}
}
-(void) dequeTransition {
if (waitingList.count > 0) {
[waitingList removeObjectAtIndex:0];
}
if (waitingList.count > 0) {
void (^transition)(void) = [waitingList objectAtIndex:0];
if (transition) {
transition();
}
}
}
@end