Представление модального контроллера представления немедленно после отклонения другого - PullRequest
37 голосов
/ 13 октября 2010

Я отказываюсь от модального контроллера вида и затем сразу представляю другой, но последний никогда не происходит.Вот код:

 [self dismissModalViewControllerAnimated:YES];

 UIImagePickerController *picker = [[UIImagePickerController alloc] init];
 picker.delegate = self;
 picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
 [self presentModalViewController:picker animated:YES];

Первый модальный VC скользит вниз, но новый picker никогда не появляется.Есть идеи о том, что происходит?

Ответы [ 8 ]

52 голосов
/ 25 августа 2011

Авг 2012 Обновление:

iOS 5 и выше представили более безопасные API для выполнения действий после того, как модалы анимированы в / из места с использованием блоков завершения:

[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];

До августа 2012 г. Ответ:

Я столкнулся с подобной проблемой при отклонении модального первого и последующем представлении модального второго в быстрой последовательности.Иногда модальное два показывалось бы после того, как модальное было отменено, а иногда модальное два вообще не появлялось, и это меня очень огорчало.

Похоже, для меня это состояние гонки ...

Установка задержки на 1+ секунды для вызывающего метода, который представил модальное два, showModalTwo, заставляло модальное два появляться каждый раз после отмены модального первого:

- (void)didDismissModalOne {
    [self performSelector:@selector(showModalTwo:) 
               withObject:someNumber 
               afterDelay:1.0f];
}

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

Проблема

Оказывается, UIViewController sиметь открытое свойство modalViewController, которое устанавливается при вызове presentModalViewController:animated: и уничтожается при вызове dismissModalViewControllerAnimated:.Подвох в том, что он не разрушается синхронно, поэтому можно создать гонку между удалением старого значения modalViewController и установкой нового значения следующим образом.

  1. Presentмодальный.myViewController.modalViewController теперь указывает на модальное значение
  2. Отклонить модальное значение.Фоновый процесс сноса myViewController.modalViewController запущен, но myViewController.modalViewController неподвижное указывает на модальное одно
  3. Текущий модальный два, myViewController.modalViewController] теперь указывает на модальное два
  4. Системные вызовы обратного вызова, настройкаmyViewController.modalViewController до nil, это прерывает процесс анимации модального два, и в результате пользователь никогда не видит его.

Гонка начинается на шаге 2 и проявляется на шаге 4.

Решение

Мое решение состояло в том, чтобы поставить условие защиты для метода, который представил модальное два, чтобы гарантировать, что myViewControoler.modalViewController было nil, прежде чем пытаться представить модальное два.

-(void)showModalTwo:(NSNumber *)aParameter {

    if (self.modalViewController) {        
            [self performSelector:@selector(showModalTwo:)
                       withObject:aParameter 
                       afterDelay:0.1f];
            return;
    }
    // You can now present the second modal safely.
}

работал как шарм.Более элегантное решение может включать тайм-аут.

Post script

Мне действительно не понравился аспект опроса этого решения.@Nimrod предлагает в принятом ответе на этот вопрос, что вы можете безопасно начать презентацию модального два из метода viewDidDisappear: модального.Мне понравился звук этого подхода, управляемого событиями, но после выполнения полной реализации в моем случае использования я подтвердил, что состояние гонки сохраняется при представлении модальных двух с использованием обратного вызова внутри viewDidDisappear:.Единственный способ быть абсолютно уверенным в том, что будет представлен модальный номер два, - это опросить в родительском контроллере представления, пока вы не будете абсолютно уверены, что self.modalViewController равно nil.Тогда и только тогда это "безопасно", чтобы совать модальные два.

16 голосов
/ 13 октября 2010

Как и другие анимированные объекты, dismissModalViewControllerAnimated не блокируется, пока контроллер представления не исчезнет. Вместо этого он «запускает» увольнение контроллера представления. Возможно, вам потребуется использовать обратный вызов в viewDidDisappear модального контроллера 1, который вызывает что-то вроде modalViewControllerDisappeared в родительском контроллере представления. В этом методе вы представляете модальный контроллер 2. В противном случае, что сказал Робот К.

14 голосов
/ 18 июля 2012
[self dismissViewControllerAnimated:YES completion:^{
    //Present the new MVC 

}];

Примечание. Доступна iOS 5.0 и более поздних версий.

5 голосов
/ 13 октября 2010
[self dismissModalViewControllerAnimated:NO];

 UIImagePickerController *picker = [[UIImagePickerController alloc] init];
 picker.delegate = self;
 picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
 [self presentModalViewController:picker animated:YES];
2 голосов
/ 13 октября 2010

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

Как я справился с этим, установив didDismissModalVC ivar на YES после того, как я позвоню dismissModalViewController. Затем в моем методе viewDidAppear: я проверяю значение ivar и представляю новый модальный контроллер вида. (Не забывая также установить значение обратно на NO, чтобы я не застрял в вечном отключении контроллеров модального представления.)

0 голосов
/ 06 мая 2017

Вот мой подход, который, кажется, хорошо работает на iOS 10. Мои обстоятельства немного отличаются, но должны работать в большинстве ситуаций.Я представляю начальный viewController как всплывающее окно, которое требует немедленного представления модального viewController.

Сначала в начальном viewController viewDidLoad просто скрываем его представление:

   view.isHidden = true

Затемна viewWillAppear представьте модальный viewController, неанимируйте и снимите с экрана представление по завершении:

   present(yourModalViewController, animated: false) { [unowned self]
       self.view.isHidden = false
    }

Возможно, вы захотите управлять своим состоянием с помощью Bool, чтобы последующие вызовыviewWillAppear не представляйте модал, но вы поняли.

0 голосов
/ 08 февраля 2016

В Свифт:

  1. Используйте dismissViewController, чтобы отклонить 1-й представленный вид.
  2. Используйте dismissViewController блок завершения для вызова функции в mainVC. Эта функция должна вызывать второй VC.

Ваш dismissViewController должен выглядеть следующим образом:

var presentingVC_Delegate: mainLists_PopoverDelegation!

@IBAction fund button_Pressed (sender: AnyObject) {
    self.dismissViewControllerAnimated(true, completion: { finished in
        self.presentingVC_Delegate.presentOtherVC()
        print("DismissVC completion block says hello")
    })
}

Где находится основной ВК, где присутствуют другие ВК:

func presentSettingsVC () {
    self.performSegueWithIdentifier("present_OtherVC", sender: nil)
}
0 голосов
/ 30 июля 2013

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

Протокол определения родительского контроллера представления:

@protocol ParentViewControllerDelegate
- (void)showModalTwo;
@end

Я реализую этот протокол в родительском контроллере вида, чтобы показать второй контроллер модального вида, и создаю свойство делегата @property id<ParentViewControllerDelegate> delegate; в первом контроллере модального вида.

Показать первый контроллер модального вида из родительского контроллера вида:

TheFirstModalViewController *controller = ...
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
...

В viewDidDisappear: методе первого контроллера модального вида, просто вызовите delegate.showModalTwo:, чтобы показать второй модальный вид из родительского контроллера вида.

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

...