iosswiftsegueuistoryboardsegueprogrammatically-created

Perform Segue is not working when I am using programmatic UI


I am creating an app for my personal project using programmaticUI and storyboard for the UI part, but I found an issue when I tried to performSegue from my "SecondViewController" to my "ThirdViewController", I added the "identifier" in my segue like usual: enter image description here

And then I called the "performSegue" from my SecondViewController:

import UIKit

class SecondViewController: UIViewController {
    
    private var myItem = [SecondItem]()
    lazy var myTableView : UITableView = {
       let myTable = UITableView()
        myTable.translatesAutoresizingMaskIntoConstraints = false
       return myTable
    }()

    private let myContentView : UIView = {
        let view = UIView()
        view.backgroundColor = .gray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    lazy var label : UILabel = {
        let myLabel = UILabel()
        myLabel.text = "Hello"
        return myLabel
    }()
    
    private let unameTextField : UITextField = {
       let txtField = UITextField()
        txtField.backgroundColor = .white
        txtField.placeholder = "Username"
        txtField.borderStyle = .roundedRect
        txtField.translatesAutoresizingMaskIntoConstraints = false
       return txtField
    }()
    
    private let pwordTxtField : UITextField = {
        let txtField = UITextField()
        txtField.placeholder = "Password"
        txtField.borderStyle = .roundedRect
        txtField.translatesAutoresizingMaskIntoConstraints = false
        return txtField
    }()
    
    private let loginBtn : UIButton = {
        let btn = UIButton(type: .system)
        btn.backgroundColor = .blue
        btn.setTitle("Login", for: .normal)
        btn.tintColor = .white
        btn.layer.cornerRadius = 5
        btn.clipsToBounds = true
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.addTarget(self, action: #selector(btnPressed), for: .touchUpInside)
        return btn
    }()
    
//I called the "performSegue" here
    @objc func btnPressed() {
        performSegue(withIdentifier: "gotoBla", sender: self)
        print("button pressed")
    }
    
    lazy var imageView : UIImageView = {
       let image = UIImage(named: "image_4")
       let imageView = UIImageView(image: image)
       imageView.translatesAutoresizingMaskIntoConstraints = false
       return imageView
    }()
    
    
    
    
    func setAutoLayout(){
        
        let guide = view.safeAreaLayoutGuide
   
        myContentView.anchor(top: guide.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: view.frame.height / 3, enableInsets: true)
        
        imageView.anchor(top: myContentView.topAnchor, left: nil , bottom: nil , right: nil , paddingTop: 10, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 80, height: 80, enableInsets: true)
        imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        unameTextField.anchor(top: imageView.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor, paddingTop: 10, paddingLeft: 20, paddingBottom: 5, paddingRight: 20, width: 0, height: 40, enableInsets: true)
        
        pwordTxtField.anchor(top: unameTextField.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40, enableInsets: true)
        
        loginBtn.anchor(top: pwordTxtField.bottomAnchor, left: myContentView.leftAnchor, bottom: nil, right: myContentView.rightAnchor , paddingTop: 20, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40, enableInsets: true)

        //TableView
        myTableView.topAnchor.constraint(equalTo: myContentView.bottomAnchor).isActive = true
        myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        myItem.append(SecondItem(text: "first"))
        myItem.append(SecondItem(text: "Second"))
        myItem.append(SecondItem(text: "Third"))

        
        view.backgroundColor = .white
        
        view.addSubview(myContentView)
        myContentView.addSubview(unameTextField)
        myContentView.addSubview(pwordTxtField)
        myContentView.addSubview(loginBtn)
        myContentView.addSubview(imageView)

        myTableView.register(SecondTableViewCell.self, forCellReuseIdentifier: K.SecondTableViewCell.identifier)
        myTableView.delegate = self
        myTableView.dataSource = self

        view.addSubview(myTableView)
        
        setAutoLayout()

        
    }
}

extension SecondViewController : UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print(indexPath.row)
    }
}

extension SecondViewController : UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        myItem.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: K.SecondTableViewCell.identifier, for: indexPath) as! SecondTableViewCell
        cell.second = myItem[indexPath.row]
        cell.selectionStyle = .none
        
        return cell
    }
}

And for the Third View Controller, i am not yet adding some code in there

import UIKit

class ThirdViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
    
}

But every time I run the app and click the login button, it always gave me this error: enter image description here

This is what my app looks like: enter image description here

Do i miss something here?


Solution

  • When posting questions here, it would be good for you to take a few minutes to review How to Ask

    However, based on the little bit of info you've provided...

    Almost certainly the problem is that you are adding View Controllers in Storyboard and then improperly trying to use them via code.

    For example, I'm guessing that you have code in your "first" view controller to load and display SecondViewController like this:

    @objc func showSecondTapped(_ sender: Any) {
        let vc = SecondViewController()
        navigationController?.pushViewController(vc, animated: true)
    }
    

    and then in SecondViewController you're trying to use the Storyboard associated segue with this:

    @objc func btnPressed(_ sender: Any) {
        performSegue(withIdentifier: "gotoBla", sender: self)
        print("button pressed")
    }
    

    However, that segue doesn't exist as part of SecondViewController code ... it is part of the Storyboard object.

    Back in your first view controller, if you load and push to SecondViewController like this:

    @objc func showSecondTapped(_ sender: Any) {
        if let vc = storyboard?.instantiateViewController(withIdentifier: "secondVC") as? SecondViewController {
            navigationController?.pushViewController(vc, animated: true)
        }
    }
    

    you will then be able to call performSegue because you loaded it from the Storyboard.