Вызов функции в базовом ViewController, так как модальный контроллер вида закрыт - PullRequest
10 голосов
/ 11 ноября 2010

У меня есть mainViewController. Я называю [self pushModalViewController: someViewController], что делает someViewController активным представлением.

Теперь я хочу вызвать функцию в mainViewController, так как someViewController исчезает с [self dismissModalViewController].

viewDidAppear не вызывается, вероятно, потому что представление уже было там, прямо под модальным представлением. Как можно вызвать функцию в mainViewController после того, как modalView закрывает себя?

Большое спасибо!

Ответы [ 3 ]

29 голосов
/ 11 ноября 2010

Этот ответ был переписан / расширен для объяснения 3 наиболее важных подходов ( @ galambalazs )

1.Блоки

Самый простой подход - использовать обратный вызов block.Это хорошо, если у вас есть только один слушатель (родительский контроллер представления), заинтересованный в увольнении.Вы даже можете передать некоторые данные с событием.

In MainViewController.m

SecondViewController* svc = [[SecondViewController alloc] init];
svc.didDismiss = ^(NSString *data) {
    // this method gets called in MainVC when your SecondVC is dismissed
    NSLog(@"Dismissed SecondViewController");
};
[self presentViewController:svc animated:YES completion:nil];

In SecondViewController.h

@interface MainViewController : UIViewController
    @property (nonatomic, copy) void (^didDismiss)(NSString *data);
    // ... other properties
@end

In SecondViewController.m

- (IBAction)close:(id)sender 
{
    [self dismissViewControllerAnimated:YES completion:nil];

    if (self.didDismiss) 
        self.didDismiss(@"some extra data");
}

2.Делегирование

Delegation является рекомендуемым шаблоном Apple:

Отклонение контроллера представленного представления

Если представленный контроллер представлений должен возвращать данные в представляющий контроллер представлений, используйте шаблон проектирования Delegation , чтобы упростить передачу.Делегирование упрощает повторное использование контроллеров представления в разных частях вашего приложения.С делегированием представленный контроллер представления хранит ссылку на объект делегата, который реализует методы из формального протокола .По мере сбора результатов представленный контроллер представления вызывает эти методы для своего делегата.В типичной реализации представляющий контроллер представления делает себя делегатом своего представленного контроллера представления.

MainViewController

In MainViewController.h

@interface MainViewController : UIViewController <SecondViewControllerDelegate>
    - (void)didDismissViewController:(UIViewController*)vc;
    // ... properties
@end

Где-то в MainViewController.m (представление)

SecondViewController* svc = [[SecondViewController alloc] init];
svc.delegate = self;
[self presentViewController:svc animated:YES completion:nil];

Где-то еще в MainViewController.m (рассказывается оувольнение)

- (void)didDismissViewController:(UIViewController*)vc
{
    // this method gets called in MainVC when your SecondVC is dismissed
    NSLog(@"Dismissed SecondViewController");
}

SecondViewController

In SecondViewController.h

@protocol SecondViewControllerDelegate <NSObject>
- (void)didDismissViewController:(UIViewController*)vc;
@end

@interface SecondViewController : UIViewController
@property (nonatomic, weak) id<SecondViewControllerDelegate> delegate;
// ... other properties
@end

Где-то в SecondViewController.m

[self.delegate myActionFromViewController:self];
[self dismissViewControllerAnimated:YES completion:nil];

(примечание: протокол с didDismissViewController: метод может быть повторно использован в вашем приложении)


3.Уведомления

Другим решением является отправка NSNotification.Это также правильный подход, он может быть проще делегирования, если вы хотите уведомить об увольнении без передачи большого количества данных.Но это основной случай использования, когда вы хотите несколько слушателей для события исключения (кроме только родительского контроллера представления).

Но убедитесь, что всегда удалите себяс NSNotificationCentre после того, как вы закончите!В противном случае вы рискуете потерпеть неудачу, будучи вызванным для уведомлений даже после того, как вас освободили. [примечание редактора]

In MainViewController.m

- (IBAction)showSecondViewController:(id)sender 
{
    SecondViewController *secondVC = [[SecondViewController alloc] init];
    [self presentViewController:secondVC animated:YES completion:nil];

    // Set self to listen for the message "SecondViewControllerDismissed"
    // and run a method when this message is detected
    [[NSNotificationCenter defaultCenter] 
     addObserver:self
     selector:@selector(didDismissSecondViewController)
     name:@"SecondViewControllerDismissed"
     object:nil];
}

- (void)dealloc
{
    // simply unsubscribe from *all* notifications upon being deallocated
    [[NSNotificationCenter defaultCenter] removeObserver:self];
} 

- (void)didDismissSecondViewController 
{
    // this method gets called in MainVC when your SecondVC is dismissed
    NSLog(@"Dismissed SecondViewController");
}

In SecondViewController.m

- (IBAction)close:(id)sender 
{
    [self dismissViewControllerAnimated:YES completion:nil];

    // This sends a message through the NSNotificationCenter 
    // to any listeners for "SecondViewControllerDismissed"
    [[NSNotificationCenter defaultCenter] 
     postNotificationName:@"SecondViewControllerDismissed" 
     object:nil userInfo:nil];
}

Надеюсь, это поможет!

3 голосов
/ 19 мая 2016

Использование exit (unwind) segue

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

Используя выходные (раскручивающиеся) сегменты, вы получаете 3 преимущества:

  1. вам не нужно писать код , чтобы закрыть модальное представлениеконтроллер и
  2. вы можете заставить iOS вызывать метод обратного вызова внутри базового контроллера представления , который представил контроллер представления модели.
  3. вы используете ту же семантику, которую вы уже использовализнать из реализации prepareForSegue:

Реализовать его всего за 2 шага

  1. Создать метод действия в контроллере представления, который представляет другой (модальный) контроллер представления:

Swift

@IBAction func unwindFromSegue(segue: UIStoryboardSegue) {
    print("Unwind from segue", segue.identifier)
}

Objective-C

- (IBAction)unwindFromSegue:(UIStoryboardSegue *)segue {
    NSLog(@"Unwind from segue %s", segue.identifier);
}
В раскадровке щелкните правой кнопкой мыши exit segue (он же раскручивается, это последний из значков в верхней части контроллера просмотра), перетащите и отпустите unwindFromSegue: на свою кнопку и выберите действие .

enter image description here

Готово!Теперь контроллер модального вида закрывается, когда вы нажимаете кнопку dismiss, и unwindFromSegue: сообщает вашему базовому контроллеру вида, что контроллер модального вида закрыт.

1 голос
/ 27 июля 2015

Вот решение обратного вызова, которое требует меньше модификаций для вашего модального и родительского: В модель .h добавить:

@property (nonatomic, copy) void (^dismissed)();

В .m модели поместите это в завершение, когда вы отклоните модал:

 [self dismissViewControllerAnimated:YES completion:^{
    if(self.dismissed)
        self.dismissed();
}];

В родительском контроллере представления при создании экземпляра вашего модального режима установите отклоненный обратный вызов:

Modal = //Init your modal
[Modal setDismissed:^{
   //do stuff you wanted when it's dimissed
}];
 [self presentViewController:Modal animated:YES completion:nil];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...