У меня очень распространенный сценарий приложения для iOS:
MainVC приложения представляет собой UITabBarController . Я установил этот VC как rootViewController в файле AppDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
window?.rootViewController = MainVC()
window?.makeKeyAndVisible()
}
Когда пользователь выходит из системы, я представляю контроллер навигации с LandingVC в качестве корневого контроллера просмотра стека навигации.
let navController = UINavigationController(rootViewController: LandingVC)
self.present(navController, animated: true, completion: nil)
Внутри LandingVC вы нажимаете кнопку входа в систему, и LoginVC помещается на вершину стека.
navigationController?.pushViewController(LoginVC(), animated: true)
Когда пользователь успешно входит в систему, я отклоняю () контроллер навигации из LoginVC.
self.navigationController?.dismiss(animated: true, completion: nil)
По сути, я пытаюсь добиться потока ниже:
![enter image description here](https://i.stack.imgur.com/XZlyM.png)
Все работает, но проблема в том, что LoginVC никогда не освобождается из памяти . Поэтому, если пользователь входит в систему и выходит 4 раза (нет причин делать это, но все же есть шанс), я увижу LoginVC 4 раза в памяти и LandingVC 0 раз.
Я не понимаю, почему LoginVC не освобождается, а LandingVC - это.
По-моему (и поправьте меня, где я ошибаюсь), поскольку представлен контроллер навигации, и он содержит 2 VC ( LandingVC и LoginVC ), когда я использую dismiss ( ) внутри LoginVC он должен отклонить навигационный контроллер, и поэтому оба содержат VC.
- MainVC : представление VC
- Контроллер навигации : представлен VC
Из документов Apple:
Представляющий контроллер представления отвечает за отклонение представленного контроллера. Если вы вызываете этот метод на самом представленном контроллере представления, UIKit просит представляющий контроллер представления обработать отклонение.
Я считаю, что что-то идет не так, когда я отключаю контроллер навигации в LoginVC . Есть ли способ вызвать dismiss () внутри MainVC (представляя VC), как только пользователь входит в систему?
PS: использование приведенного ниже кода не поможет, так как он появляется в корневом контроллере представления стека навигации, который является LandingVC; а не на MainVC.
self.navigationController?.popToRootViewController(animated: true)
Любая помощь будет принята с благодарностью!
====================================
Мой логинVC код:
import UIKit
import Firebase
import NotificationBannerSwift
class LoginVC: UIViewController {
// reference LoginView
var loginView: LoginView!
override func viewDidLoad() {
super.viewDidLoad()
// dismiss keyboard when clicking outside textfields
self.hideKeyboard()
// setup view elements
setupView()
setupNavigationBar()
}
fileprivate func setupView() {
let mainView = LoginView(frame: self.view.frame)
self.loginView = mainView
self.view.addSubview(loginView)
// link button actions from LoginView to functionality inside LoginViewController
self.loginView.loginAction = loginButtonClicked
self.loginView.forgotPasswordAction = forgotPasswordButtonClicked
self.loginView.textInputChangedAction = textInputChanged
// pin view
loginView.translatesAutoresizingMaskIntoConstraints = false
loginView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
loginView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
loginView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
loginView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
fileprivate func setupNavigationBar() {
// make navigation controller transparent
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
// change color of text
self.navigationController?.navigationBar.tintColor = UIColor.white
// add title
navigationItem.title = "Login"
// change title font attributes
let textAttributes = [
NSAttributedStringKey.foregroundColor: UIColor.white,
NSAttributedStringKey.font: UIFont.FontBook.AvertaRegular.of(size: 22)]
self.navigationController?.navigationBar.titleTextAttributes = textAttributes
}
fileprivate func loginButtonClicked() {
// some local authentication checks
// ready to login user if credentials match the one in database
Auth.auth().signIn(withEmail: emailValue, password: passwordValue) { (data, error) in
// check for errors
if let error = error {
// display appropriate error and stop rest code execution
self.handleFirebaseError(error, language: .English)
return
}
// if no errors during sign in show MainTabBarController
guard let mainTabBarController = UIApplication.shared.keyWindow?.rootViewController as? MainTabBarController else { return }
mainTabBarController.setupViewControllers()
// this is where i dismiss navigation controller and the MainVC is displayed
self.navigationController?.dismiss(animated: true, completion: nil)
}
}
fileprivate func forgotPasswordButtonClicked() {
let forgotPasswordViewController = ForgotPasswordViewController()
// present as modal
self.present(forgotPasswordViewController, animated: true, completion: nil)
}
// tracks whether form is completed or not
// disable registration button if textfields not filled
fileprivate func textInputChanged() {
// check if any of the form fields is empty
let isFormEmpty = loginView.emailTextField.text?.count ?? 0 == 0 ||
loginView.passwordTextField.text?.count ?? 0 == 0
if isFormEmpty {
loginView.loginButton.isEnabled = false
loginView.loginButton.backgroundColor = UIColor(red: 0.80, green: 0.80, blue: 0.80, alpha: 0.6)
} else {
loginView.loginButton.isEnabled = true
loginView.loginButton.backgroundColor = UIColor(red: 32/255, green: 215/255, blue: 136/255, alpha: 1.0)
}
}
}