弱可选变量即使赋值后也显示为零

  • 本文关键字:显示 赋值 变量 ios swift
  • 更新时间 :
  • 英文 :


我有一个LoginCordinator类,它的start((方法实例化LoginViewController。但是,即使在从LoginCordinator分配了LoginViewController中的协调器变量之后,"有时"协调器变量在视图控制器中为零。

我所说的"有时"是指,当我调试并在start((方法中保留断点时,就会分配值。

这是我的登录协调员

class LoginCoordinator: Coordinator {
var navigationController: UINavigationController
weak var parent: MainCoordinator?
var childCoordinators: [Coordinator]?

init(navController: UINavigationController) {
self.navigationController = navController
}
func start() {
let vc: LoginViewController = UIStoryboard.main.instantiateViewController()
vc.coordinator = self
navigationController.pushViewController(vc,animated: true)
}
func goToSignUp() {
let signUpCoordinator = SignUpCoordinator(navController: navigationController)
childCoordinators?.append(signUpCoordinator)
signUpCoordinator.start()
}
func goToHomeVC() {
let homeCoordinator = HomeCoordinator(navControl: navigationController)
childCoordinators?.append(homeCoordinator)
homeCoordinator.start()
}
}

这是我的LoginViewController

class LoginViewController: UIViewController {
@IBOutlet weak private var userName: HubTextField!
@IBOutlet weak private var password: HubTextField!
@IBOutlet weak private var forgotPassword: UILabel!
@IBOutlet weak var loginButton: HubButton!
var viewModel: LoginSignupVM = .init(totalItem: 2)
weak var coordinator: LoginCoordinator?
fileprivate func setupForgotPassword() {
forgotPassword.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(forgotTapped))
forgotPassword.addGestureRecognizer(tapGesture)
}
override func viewDidLoad() {
super.viewDidLoad()
loginButton.appearance = Appearance(cornerRadius: loginButton.frame.height/2)
loginButton.setTitle(TitleText.loginText, for: .normal)
loginButton.isEnabled = false
setupTextField()
hideKeyboardWhenTappedAround()
setupForgotPassword()
setupNavigationBar()

// MARK: remove this later
userName.text = "hirak@gmail.co"
password.text = "asdfg123"
}
private func setupNavigationBar() {
let titleView = UILabel(frame: .zero)
titleView.text = "Login Up"
titleView.font = UIFont.systemFont(ofSize: 20)
navigationItem.titleView = titleView
rightButton()
}
fileprivate func rightButton() {
let rightButton = UIBarButtonItem(title: "signUp", style: .plain, target: self, action: #selector(goToSignUPScreen))
rightButton.title = "sign Up"
navigationItem.rightBarButtonItem = rightButton
}
@objc private func goToSignUPScreen() {
coordinator?.goToSignUp()
}
@objc private func backButtonClicked() {
navigationController?.popViewController(animated: true)
}
@objc private func forgotTapped() {
//MARK: todo forgot password
}
private func assignTags() {
userName.tag = 0
password.tag = 1
}
private func setupTextField() {
userName.placeHolder = TitleText.email
userName.textFieldType = .email
userName.delegate = self
password.placeHolder = TitleText.password
password.textFieldType = .password
password.delegate = self
assignTags()
}
private func goToHomeViewController() {
coordinator?.goToHomeVC()
}
@IBAction func onLoginClick(_ sender: Any) {
//MARK: todo login click change hardcoded verification
if let email = userName.text, let password = password.text {
if email == "hirak@gmail.co" && password == "asdfg123" {
goToHomeViewController()
}
}
}
}
extension LoginViewController: ValidatorButton {
func addNewValidated(tag: Int, result: ValidationResult) {
viewModel.validationList[tag] = result
loginButton.isEnabled = viewModel.loginButtonEnabled()
}
}

登录协调员从MainCoordinator调用为:

class MainCoordinator: Coordinator {
var isLogin: Bool = false
var navigationController: UINavigationController
var childCoordinators: [Coordinator]? = []
let window: UIWindow?
init(navController: UINavigationController, window: UIWindow) {
self.navigationController = navController
self.window = window
}
func start() {
if isLogin {
let child = HomeCoordinator(navControl: navigationController)
childCoordinators?.append(child)
child.start()
} else {
let child = LoginCoordinator(navController: 
navigationController)
childCoordinators?.append(child)
child.start()
}
} 
}

从场景中调用MainCoordinator如下:

func scene(_ scene: UIScene, willConnectTo session: 
UISceneSession, options connectionOptions: 
UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: scene)
self.window = window

let navigationController = UINavigationController()
let mainCoordinator = MainCoordinator(navController: 
navigationController,window: window)
mainCoordinator.start()
window.rootViewController = navigationController
window.makeKeyAndVisible()
}

mainCoordinator被声明为willConnectTo委托方法中的局部变量:

let mainCoordinator = MainCoordinator(navController: 
navigationController,window: window)

这意味着它可以在willConnectTo中的最后一次访问之后被解除分配。

由于mainCoordinator是对LoginCoordinator的唯一强引用,因此它也将被释放。这就是您在视图控制器中看到nil的原因——此时,mainCoordinator已被解除分配。

您仍然可以在LoginCoordinator.start中看到一个非零值,因为此时mainCoordinator.start还没有完成,所以mainCoordinator还没有解除分配。

要解决此问题,可以通过声明一个名为mainCoordinator:的属性,使场景代理拥有对主协调器的强引用

var mainCoordinator: MainCoordinator!
// in willConnectTo:
mainCoordinator = MainCoordinator(navController: 
navigationController,window: window)

最新更新