为什么 ui 元素以 swift 编程方式在视图控制器之间共享?

Why the ui elements are shared between view controllers in swift programmatic way?

我试图在 swift 中以编程方式导航视图控制器。所以,我这次测试的目的是

所以这是我的 AppDelegate.swift。我创建了导航控制器并嵌入了 ViewController.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow(frame: UIScreen.main.bounds)

        let navigationController = UINavigationController();
        let mainViewController = ViewController();
        let loginViewController = LoginViewController();
        navigationController.viewControllers = [ mainViewController, loginViewController ];
        self.window?.rootViewController = navigationController;
        self.window?.makeKeyAndVisible()

        return true
    }

然后在视图控制器中

let button: UIButton = {
        let button = UIButton(frame: CGRect(x: 120, y: 120, width: 50, height: 50));
        button.setTitle("Login", for: .normal);
        button.layer.borderColor = UIColor.lightGray.cgColor;
        button.translatesAutoresizingMaskIntoConstraints = false;
        button.backgroundColor = UIColor.red;
        button.layer.cornerRadius = 5;

        return button;
    }();

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white;
        view.addSubview(button);


        button.addTarget(self, action: #selector(loginPressed(_sender:)), for: .touchUpInside);
        // Do any additional setup after loading the view.
    }

    @IBAction func loginPressed(_sender: UIButton) {
        print("clicked");
        let loginViewController = LoginViewController();
        self.navigationController?.pushViewController(loginViewController, animated: true);
    }

并且在LoginViewController

let emailLabel: UILabel = {
        let label = UILabel(frame: CGRect(x: 150, y: 150, width: 150, height: 150));
        label.text = "Email address";
        return label;
    }();

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(emailLabel);
        print("this is loginViewController");
    }

这是我的结果。在 ViewController

并在登录中ViewController。

所以这是我的问题:为什么按钮会出现在登录ViewController中?为什么 uielement 在视图控制器之间共享?

注意:我尝试在 google 中搜索。也许因为我是一名网络开发人员,我可能没有用正确的词进行搜索。

首先尝试使用 backgroundColor 进行调试并检查视图是否透明。

其次,从 navigationController.viewControllers = [ mainViewController, loginViewController ]; 中删除 loginViewController,因为这样做是将 UIViewController 推入堆栈。

无论如何,当您使用 let loginViewController = LoginViewController();

推送时,您正在创建一个新的 LoginViewController 实例

当您在推送后打印 navigationController.viewControllers 时,您会得到类似 [mainViewController, loginViewController, loginViewController] 的内容,我认为这不是您想要的。

第三,@IBAction 用于Storyboard。为什么你不在 generell 中使用故事板?只需点击几下,无需一行代码,即可实现您想要实现的目标。

运行使用您发布的确切代码,初始视图将是您的LoginViewController(不是您的"Main"视图控制器) 并且屏幕将变黑。

所以,要修复那里的东西...

AppDelegate 中不要尝试创建 LoginViewController - 仅创建和设置您的 "main" VC:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    window = UIWindow(frame: UIScreen.main.bounds)

    let navigationController = UINavigationController();
    let mainViewController = ViewController();

    // don't try to create login view here...
    //let loginViewController = LoginViewController();
    //navigationController.viewControllers = [ mainViewController, loginViewController ];

    // set only your first controller
    navigationController.viewControllers = [ mainViewController ];

    self.window?.rootViewController = navigationController;
    self.window?.makeKeyAndVisible()

    return true
}

现在,当您 运行 应用程序将显示带有 Login 按钮的 "main" VC 时的初始视图...但是,点击该按钮将推送黑屏,因为你没有给 LoginViewController 背景颜色:

class LoginViewController: UIViewController {

    let emailLabel: UILabel = {
        let label = UILabel(frame: CGRect(x: 150, y: 150, width: 150, height: 150));
        label.text = "Email address";
        return label;
    }();

    override func viewDidLoad() {
        super.viewDidLoad()

        // set background to green, to make it really obvious
        view.backgroundColor = .green

        view.addSubview(emailLabel);
        print("this is loginViewController");
    }
}

如果您仍然看到 Login 按钮和电子邮件标签,和/或背景不是绿色,我怀疑您开始是在 Storyboard 中布置视图控制器但没有清除 Main Interface 在项目设置(常规选项卡)中:

如果 Main Interface 框不为空,请删除其中的内容并再次 运行 您的应用(进行上述更改)。


编辑

这是一个完整的示例,使用您的代码和我描述的编辑。

  • 创建一个新项目
  • 删除 Main.storyboard
  • 将下面的 AppDelegate 代码复制并粘贴到 AppDelegate.swift
  • 将下面的 ViewController 代码复制并粘贴到 ViewController.swift
  • 从项目设置/常规Main Interface中删除单词Main
  • 运行 应用

看看你是否得到了你想要的。


AppDelegate

//
//  AppDelegate.swift
//  NewProject
//
//  Created by Don Mag on 8/6/19.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        window = UIWindow(frame: UIScreen.main.bounds)

        let navigationController = UINavigationController();
        let mainViewController = ViewController();

        // don't try to create login view here...
        //let loginViewController = LoginViewController();
        //navigationController.viewControllers = [ mainViewController, loginViewController ];

        // set only your first controller
        navigationController.viewControllers = [ mainViewController ];

        self.window?.rootViewController = navigationController;
        self.window?.makeKeyAndVisible()

        return true
    }
    func applicationWillResignActive(_ application: UIApplication) {
    }
    func applicationDidEnterBackground(_ application: UIApplication) {
    }
    func applicationWillEnterForeground(_ application: UIApplication) {
    }
    func applicationDidBecomeActive(_ application: UIApplication) {
    }
    func applicationWillTerminate(_ application: UIApplication) {
    }
}

ViewController

//
//  ViewController.swift
//  NewProject
//
//  Created by Don Mag on 8/7/19.
//

import UIKit

class ViewController: UIViewController {

    let button: UIButton = {
        let button = UIButton(frame: CGRect(x: 120, y: 120, width: 50, height: 50));
        button.setTitle("Login", for: .normal);
        button.layer.borderColor = UIColor.lightGray.cgColor;
        button.translatesAutoresizingMaskIntoConstraints = false;
        button.backgroundColor = UIColor.red;
        button.layer.cornerRadius = 5;

        return button;
    }();

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white;
        view.addSubview(button);


        button.addTarget(self, action: #selector(loginPressed(_sender:)), for: .touchUpInside);
        // Do any additional setup after loading the view.
    }

    @IBAction func loginPressed(_sender: UIButton) {
        print("clicked");
        let loginViewController = LoginViewController();
        self.navigationController?.pushViewController(loginViewController, animated: true);
    }

}

class LoginViewController: UIViewController {

    let emailLabel: UILabel = {
        let label = UILabel(frame: CGRect(x: 150, y: 150, width: 150, height: 150));
        label.text = "Email address";
        return label;
    }();

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .green
        view.addSubview(emailLabel);
        print("this is loginViewController");
    }

}

在花了更多时间并从@DonMag 的回答中寻找我做错了什么之后,我试图推送的视图控制器继承了 ViewController class 而不是实际的 UIViewController .