我有一个非常常见的 iOS 应用场景:
The MainVC该应用程序的一个UITabBar控制器。我在 AppDelegate.swift 文件中将此 VC 设置为 rootViewController:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
window?.rootViewController = MainVC()
window?.makeKeyAndVisible()
}
当用户注销时,我会显示一个导航控制器登陆创投作为导航堆栈的根视图控制器。
let navController = UINavigationController(rootViewController: LandingVC)
self.present(navController, animated: true, completion: nil)
Inside 登陆创投您单击“登录”按钮,然后LoginVC被压入栈顶。
navigationController?.pushViewController(LoginVC(), animated: true)
当用户成功登录时,我从 LoginVC 内部解雇()导航控制器。
self.navigationController?.dismiss(animated: true, completion: nil)
基本上,我试图实现以下流程:
一切正常,但问题是LoginVC从来没有从内存中释放。因此,如果用户登录并注销 4 次(没有理由这样做,但仍然有机会),我会看到LoginVC内存中4次,LandingVC 0次。
我不明白为什么LoginVC没有被释放,但是登陆创投 is.
在我看来(并纠正我错误的地方),因为导航控制器已呈现并且它包含 2 个 VC(登陆创投 and LoginVC),当我在里面使用dismiss()时LoginVC它应该关闭导航控制器,因此两者都包含 VC。
来自苹果文档:
呈现视图控制器负责解除它呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,UIKit 会要求呈现的视图控制器处理解雇。
我相信当我关闭导航控制器时出现了问题LoginVC。有没有办法在里面触发dismiss()MainVC(出示 VC)用户一登录?
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)
}
}
}