0

I have two viewControllers: the first one has a tableView in it and the second one has a textField with an action, if there is a specific text inserted in the textFiled, I want to call loadData1() function which has orderTable.reloadData() to reload the tableView from the logInviewController, but it returns nil when I call it.

tableViewController code :

    import UIKit
    import FirebaseFirestore
    import Firebase
    import FirebaseAuth

    class orderTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {

    @IBOutlet var orderTable: UITableView!
    var db: Firestore!
    var firstName = [String]()
    var lastName = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
    orderTable.register(UINib(nibName: "Order1TableViewCell", bundle: nil) , forCellReuseIdentifier: "orderCell")

     }
    
     func loadData1() {
        
      Firestore.firestore().collection("hola").getDocuments() { [self]
            
            (querySnapshot, err) in
            
            if let err = err
            
            {
                print("Error getting documents: \(err)");
            }
            else
            {
     for document in querySnapshot!.documents {
                    self.firstName.append(document.get("firstname") as? String ?? "")
                    self.lastName.append(document.get("lastname") as? String ?? "")
      }
     }
            
            orderTable.reloadData()       // from here i got Unexpectedly found nil while unwrapping an Optional value:
     }
      }
     }

    
    }

logInViewController code :

    import UIKit
    import Firebase
    import FirebaseAuth

    class logInViewController: UIViewController, UITextFieldDelegate {
    
    
    @IBOutlet var userNameField: UITextField!
    @IBOutlet var passwordField: UITextField!
    @IBOutlet var logInButton: UIButton!
    var db: Firestore!
    var order: orderTableViewController!
    
    override func viewDidLoad() {
    super.viewDidLoad()
        

    }
    
    @IBAction func textfieldDidChange(_ sender: Any) {
        
        print(userNameField?.text ?? "") 

        if userNameField.text == "v@v.com" {
            let i = orderTableViewController()
            i.loadData1()
            
          }
      }
    


    }
NicolasElPapu
  • 1,612
  • 2
  • 11
  • 26
Ahmad
  • 1
  • 2
  • You should capitalize your class names. I'm not clear what you're expecting to happen when you call `orderTableViewController()`. Shouldn't this be a reference to your table view? Why are you calling it as a method? – jnpdx Jan 27 '21 at 00:26
  • @jn_pdx because i want to call loadData1() in logInViewController and loadData1() its from orderTableViewController – Ahmad Jan 27 '21 at 00:31
  • But you're just creating a new instance of it and calling loadData1() on it? Shouldn't you be calling that on `order` instead? – jnpdx Jan 27 '21 at 00:44
  • @jn_pdx yes i tried it and it gives me the same error – Ahmad Jan 27 '21 at 00:47
  • You're not showing the table view code where you render the data. If you're getting `found nil while unwrapping an Optional value` like you say, you need to show where you're force unwrapping an optional (look for an `!`) – jnpdx Jan 27 '21 at 00:49
  • @jn_pdx please check tableViewController code , i put a comment where i get the error and i already tried to force unwrap it with ! but it gives me the same error – Ahmad Jan 27 '21 at 00:54
  • I'm not suggesting you force unwrap. The error says that you're getting nil because it is already being force unwrapped. Your included `TableViewController` code is incomplete. – jnpdx Jan 27 '21 at 00:59
  • @jn_pdx ok please how can i fix this error , im trying to fix it since 1 month, please help me – Ahmad Jan 27 '21 at 01:02
  • @jn_pdx i did alot of research in stackOverFlow and google also youtube and udemy but i didn't find any solution , please help – Ahmad Jan 27 '21 at 01:03
  • I'm trying to help, but as far as I can tell, you haven't posted all of your relevant code. – jnpdx Jan 27 '21 at 01:06
  • @Rob how can i fix it ? – Ahmad Jan 27 '21 at 01:07
  • @Rob i will try it – Ahmad Jan 27 '21 at 01:08
  • @Rob i tried to change my class to OrderTableViewController but it is the same error again – Ahmad Jan 27 '21 at 01:10
  • @Rob ok how can i fix the error Unexpectedly found nil while unwrapping an Optional value: – Ahmad Jan 27 '21 at 01:13
  • See answers like https://stackoverflow.com/q/5210535/1271826. They talk about passing data between view controllers, but the pattern they discuss for passing data backwards to prior view controllers is the same way we call methods in prior view controllers, too. If you search Stack Overflow (and the web in general) for iOS programming questions about passing data between view controllers, you should find plenty of references. This is a very common pattern, so it is good to familiarize yourself with these practices... – Rob Jan 27 '21 at 01:29

2 Answers2

1

Where you have let i = orderTableViewController(), you are not referencing your existing table view controller, but rather are creating a new one, except this time it is not instantiated in conjunction with the storyboard scene, and thus all of your @IBOutlet references will be nil. Attempts to reference those @IBOutlet references will fail.

To fix this, you should pass a reference for the first view controller to the second one, using a protocol rather than an explicit class name, and then the second view controller can call a method in the first. Thus:

  1. Create class protocol, e.g. LoginViewControllerDelegate:

    protocol LoginViewControllerDelegate: class { }
    
  2. Give that protocol one method requirement, loadData1:

    protocol LoginViewControllerDelegate: class { 
        func loadData1()
    }
    
  3. Make your first view controller conform to that protocol:

    extension OrderTableViewController: LoginViewControllerDelegate { 
        func loadData1() {
            ... your implementation here ...
        }
    }
    
  4. Create a property in the second view controller, that LoginViewController, for this delegate-protocol reference, e.g.:

    weak var delegate: LoginViewControllerDelegate?
    
  5. When first view controller instantiates second, set this delegate property (e.g. if doing segues, it would be in prepareForSegue):

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? LoginViewController {
            destination.delegate = self
        }
    }
    
  6. The second view controller then would call delegate?.loadData1() rather than i.loadData1().

Rob
  • 415,655
  • 72
  • 787
  • 1,044
0

If you do what I understand then you can do this. But you should use delegate or closure callback to do that.

@IBAction func textfieldDidChange(_ sender: Any) {
    
    print(userNameField?.text ?? "") 

    if userNameField.text == "v@v.com" {
      if let i = order {
        i.loadData1()
      } 
    }
  }
}
Ten
  • 1,426
  • 1
  • 14
  • 18