2016-02-15 10 views
11

W moim TabBarViewController tworzę kontroler UINavigationController i przedstawiam go jako modalny.Jak poprawnie odrzucić UINavigationController, który jest prezentowany jako modalny?

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) 

Wewnątrz mojego MessageViewController, to jak chcę go odwołać:

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") 
} 

Problemem jest to, że kiedy się do głównego View Controller i próbować odwołać zarówno dziecka i UINavigationController, mój deinit nie zostanie wywołany. Coś trzyma się go - najprawdopodobniej UINavigationController

Odpowiedz

11

Twoja hierarchia kontrolerów wygląda następująco:

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

Teraz, jeśli jesteś wewnątrz MessagesViewController, a następnie jego navigationController jest jeden, który jest przedstawiony i to jest jeden powinien być odwoływanie ale nazywając dismiss na MessagesViewController powinno działać zbyt.

Problem polega jednak na tym, że odwołanie kontrolera nawigacji nie spowoduje usunięcia kontrolerów widoku. Wydaje się trzymają do kontrolera nawigacji (ponieważ jesteś prezentując je za pomocą self.navController) tak państwo będzie stać

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

Aby poprawnie zniszczyć MessagesViewController trzeba będzie albo puścić navController lub trzeba będzie pop do rootowania (usuwając w ten sposób MessagesViewController z hierarchii widoków).

Typowym rozwiązaniem byłoby w ogóle nie zapisać odniesienia do . Podczas prezentacji zawsze można utworzyć nowy UINavigationController. Innym rozwiązaniem jest użycie delegata - zamiast odwoływania od wewnątrz MessagesViewController, niech oddzwoni do prezentera, który nazwałbym

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

Dzięki. Jeśli mam wiele kontrolerów widoku w stosie, ale mój delegat wywołuje 'dismissViewControllerAnimated''', a następnie ustawia go na zero, czy deinituje ** wszystkie ** kontrolerów widoku w stosie? – TIMEX

+0

Po zwolnieniu wszystkich odwołań do 'navController', wszystkie kontrolery widoku zostaną zniszczone, jeśli nie będziesz ich trzymał gdzie indziej. – Sulthan

+0

Nie można także odrzucić kontrolera widoku, który został ustawiony jako kontroler rootview. Więc jeśli: –

7

Spróbuj

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

Proponuję użyć innego inicjatora dla UINavigationController:

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

Aby dimiss, po prostu zrobić

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

Nie trzeba mieć element dla navController. Użyj poniższego kodu, aby zaprezentować swój MessagesViewController.

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

Twój oddalić widok kod kontrolera będzie

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

jeśli chcesz po prostu przedstawić viewcontroller, następnie bezpośrednio można przedstawić tę viewcontroller i nie ma potrzeby podejmowania kontroler nawigacyjny dla danego viewcontroller.

Ale kiedy potrzebujemy nawigować z tego przedstawionego kontrolera widoku, musimy przyjąć kontroler widoku jako widok główny kontrolera nawigacyjnego.Abyśmy mogli poruszać się po tym przedstawionym kontrole widoku.

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

iz tego przedstawionego kontrolera widoku można przejść do innego kontrolera widoku, a także pop z innego kontrolera widoku.

I od prezentowanego kontrolera widoku, tutaj messageVC, musimy odwołać że

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

który odrzuci messageVC powodzeniem i wrócić do pochodzenia viewcontroller skąd zaprezentowaliśmy messageVC.

To jest właściwy przepływ do wykonania presentViewController z kontrolerem nawigacyjnym, aby kontynuować nawigację między kontrolerami widoku.

I więcej, jeśli nie masz pewności, że komunikat vC jest prezentowany lub przesyłany, możesz go sprawdzić: by this answer.

A Swift wersję, aby sprawdzić, że jest

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 
} 

Więc nasz ostateczny środek do odwołania jest jak

func swipedRightAndUserWantsToDismiss() { 

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

     } 
2

ten sposób mogę rozwiązać ten problem w Objective C

Ty można zadzwonić pod numer odrzućViewControllerAnimated: NO na swoim self.navigationController i tself.

Cel C

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

Swift

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

Swift 3 uzyskuje się:

self.navigationController?.dismiss(animated: true, completion: nil) 
Powiązane problemy