我有一个非常常见的 iOS 应用场景:
该应用程序的MainVC是一个UITabBarController。我在 AppDelegate.swift 文件中将此 VC 设置为 rootViewController:
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 中,您单击 Login 按钮,LoginVC被推到堆栈的顶部。
navigationController?.pushViewController(LoginVC(), animated: true)
当用户成功登录时,我从 LoginVC 内部解除()导航控制器。
self.navigationController?.dismiss(animated: true, completion: nil)
基本上,我正在尝试实现以下流程:
一切正常,但问题是LoginVC永远不会从内存中释放。因此,如果用户登录和注销 4 次(没有理由这样做但仍有机会),我将在内存中看到 4 次 LoginVC 和 0 次 LandingVC 。
我不明白为什么LoginVC没有被释放,但LandingVC是。
在我看来(并纠正我的错误),因为导航控制器出现并且它包含 2 个 VC(LandingVC和LoginVC),当我在LoginVC中使用 dismiss() 时,它应该关闭导航控制器,因此两者都包含 VC .
- MainVC : 展示 VC
- 导航控制器:介绍 VC
来自苹果文档:
呈现视图控制器负责关闭它呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,UIKit 会要求呈现的视图控制器处理解除。
我相信当我在LoginVC中关闭导航控制器时出了点问题。有没有办法在用户登录后立即在MainVC(呈现 VC)中触发dismiss()?
PS:使用下面的代码不会成功,因为它会弹出到导航堆栈的根视图控制器,即 LandingVC;而不是 MainVC。
self.navigationController?.popToRootViewController(animated: true)
任何帮助将非常感激!
=====================================
我的 LoginVC 代码:
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)
}
}
}