2016-02-15 3 views
11

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

var navController = UINavigationController() 
let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController 
self.presentViewController(self.navController, animated: false, completion: nil) 
self.navController.pushViewController(messageVC, animated: false) 

Внутри моей MessageViewController, это то, как я хочу, чтобы закрыть его:

func swipedRightAndUserWantsToDismiss(){ 
    if self == self.navigationController?.viewControllers[0] { 
     self.dismissViewControllerAnimated(true, completion: nil) //doesn't deinit 
    }else{ 
     self.navigationController?.popViewControllerAnimated(true) //deinits correctly 
    } 
} 

deinit{ 
    print("Deinit MessagesViewController") 
} 

Проблема заключается в том, что, когда я получаю к корневому View Controller и попытаться отклонить оба ребенка и UINavigationController, мой MessagesViewController deinit не вызывается. Что-то держит на него - скорее всего UINavigationController

ответ

11

Ваша иерархия контроллера выглядит так:

UITabViewController 
    | 
    | presents 
    | 
UINavigationController 
    | 
    | contains view controllers 
    | 
[root, MessagesViewController] 

Теперь, если вы находитесь внутри MessagesViewController, то его navigationController является тот, который будет представлен и это один вы должны отклоняя но называть dismiss на MessagesViewController должен работать тоже.

Однако проблема в том, что отклонение контроллера навигации не приведет к удалению его контроллеров представлений. Кажется, что вы держите в навигационном контроллере (так как вы представляете его с помощью self.navController), так что государство станет

UITabViewController 
    | 
    | self.navController holds a reference to 
    | 
UINavigationController 
    | 
    | contains view controllers 
    | 
[root, MessagesViewController] 

Чтобы правильно уничтожить MessagesViewController вам придется либо отпустить navController или вам придется поп (таким образом удаляя MessagesViewController из иерархии представлений).

Типичным решением является не сохранение ссылки на navController. При представлении вы всегда можете создать новый UINavigationController. Другим решением является использование делегата - вместо того, чтобы увольнять внутри MessagesViewController, пусть перезвонит ведущий, который бы назвал

self.navController.dismissViewControllerAnimated(true, completion: { 
    self.navController = nil; 
}); 
+0

спасибо. Если у меня есть много контроллеров представлений в стеке, но мой делегат вызывает '' 'rejectViewControllerAnimated''', а затем устанавливает его в nil, будет ли он деинировать ** все ** контроллеров представления в стеке? – TIMEX

+0

Когда вы отпустите все ссылки на 'navController', все его контроллеры будут уничтожены, если вы не держите их где-то в другом месте. – Sulthan

+0

Вы также не сможете убрать контроллер представления, который был настроен как rootviewcontroller. Так что если: –

7

Попробуйте

func swipedRightAndUserWantsToDismiss(){ 
    self.navigationController.dismissViewControllerAnimated(false, completion:nil); 
} 
2

Я предлагаю вам использовать другой инициализатора для UINavigationController:

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController 
let navController = UINavigationController(rootViewController: messageVC) 
self.presentViewController(self.navController, animated: true, completion: nil) 

Для dimiss, просто сделать

func swipedRightAndUserWantsToDismiss() { 
    self.navigationController.dismissViewControllerAnimated(true, completion: nil) 
} 
5

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

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController 
let pesentingNavigationController = UINavigationController(rootViewController: messageVC) 
self.presentViewController(pesentingNavigationController, animated: true, completion: nil) 

Ваше смещать вид контроллер код будет

func swipedRightAndUserWantsToDismiss() { 
    self.navigationController.dismissViewControllerAnimated(true, completion: nil) 
} 
2

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

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

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController 
let MynavController = UINavigationController(rootViewController: messageVC) 
self.presentViewController(MynavController, animated: true, completion: nil) 

и с представленного контроллера представлений вы можете нажать на другой контроллер представления, а также поплыть с другого контроллера.

И из представленного контроллера представления, здесь messageVC, мы должны уволить, что, как

func swipedRightAndUserWantsToDismiss() { 
    self.dismissViewControllerAnimated(true, completion: nil) 
} 

который уволит messageVC успешно и вернуться к происхождению ViewController, откуда мы представили messageVC.

Это правильный поток для выполнения presentViewController с навигационным контроллером для продолжения навигации между контроллерами.

И если вы не уверены, что messageVC представлен или нажат, вы можете проверить его by this answer.

И быстрая версия, чтобы проверить, что это

func isModal() -> Bool { 
    if((self.presentingViewController) != nil) { 
     return true 
    } 

    if(self.presentingViewController?.presentedViewController == self) { 
     return true 
    } 

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) { 
     return true 
    } 

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) { 
     return true 
    } 

    return false 
} 

Таким образом, наша окончательное решение уволить, как

func swipedRightAndUserWantsToDismiss() { 

      if self.isModal() == true { 
       self.dismissViewControllerAnimated(true, completion: nil) 
      } 
      else { 
       self.navigationController?.popViewControllerAnimated(true) 
      } 

     } 
2

Это, как я могу решить эту проблему в Objective C.

Вы может позвонить увольнениеПросмотрСообщения: NO на вашем self.navigationController i tself.

цель C

[self.navigationController dismissViewControllerAnimated:NO completion:nil]; 

Свифта

self.navigationController.dismissViewControllerAnimated(false, completion: nil) 
2

В Swift 3 это достигается с помощью:

self.navigationController?.dismiss(animated: true, completion: nil)