-1

I have setup a UITextField in a ViewController and Xcode doesn't show me errors. But when I run my app and load the Screen the app crashes with the error message:

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

This is my code:

import Foundation
import UIKit

class LoginScreenViewController: UIViewController, UITextFieldDelegate{
    
    @IBOutlet weak var phoneAndEmailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        phoneAndEmailTextField.delegate = self
        passwordTextField.delegate = self
    }

    @IBAction func phoneAndEmailTextFieldAction(_ sender: UITextField) {
        phoneAndEmailTextField.endEditing(true)
        print(phoneAndEmailTextField.text!)
    }

    @IBAction func passwordTextFieldAction(_ sender: UITextField) {
        passwordTextField.endEditing(true)
        print(passwordTextField.text!)
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        phoneAndEmailTextField.endEditing(true)
        passwordTextField.endEditing(true)
        
        return true
    }

    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        if textField.text != "" {
            return true
        }else {
            return false
        }
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        // sql
    }
}

This is are the referenced Outlets of one TextField. The other one is the same... Storyboard

David
  • 193
  • 1
  • 8
  • there is probably no text in your textfields and force unwrapping them like this `print(phoneAndEmailTextField.text!)` and `print(passwordTextField.text!)` is what is causing your crash probably. Safely unwrap them prior to printing and see if your crashes get resolved. – Shawn Frank Feb 15 '22 at 13:04
  • But the View doesn't even load. The crash is at the delegate when I try to load the view, so the print statements doesn't get triggered. – David Feb 15 '22 at 13:22
  • Find which line causes the iissue: `phoneAndEmailTextField.delegate = self`? Then `phoneAndEmailTextField` is nil, and you wrote that it shouldn't with `UITextField!`. Question is how did you load/created `LoginScreenViewController`? Did you connected correctly the IBOutlets in Storyboard/Xib? – Larme Feb 15 '22 at 13:44
  • Which specific line is crashing? – Duncan C Feb 15 '22 at 14:01
  • The phoneAndEmailTextField.delegate = self gets the crash. I also though about connecting the IBOutlets could be the issue but I deleted them and reconnected them a few times... – David Feb 15 '22 at 14:06
  • Edit your question to include that information. People reading this thread should not have to wade through a whole series of comments to understand your question fully. – Duncan C Feb 15 '22 at 14:10
  • Then, how is shown `LoginScreenViewController`? How is it created? Did you write `LoginScreenViewController()`? Instead of initializing it from the storyboard? – Larme Feb 15 '22 at 14:36
  • I've just presenting it with present(LoginScreenViewController(), animated: true) – David Feb 15 '22 at 14:38
  • So you are doing indeed `LoginScreenViewController()`. And how should it know that it needs to be linked with that specific storyboard? What if there was another storyboard with a similar one, but with different colors? So you need to instatiante the storybooard, then the viewcontroller from it. See https://stackoverflow.com/questions/24035984/instantiate-and-present-a-viewcontroller-in-swift – Larme Feb 15 '22 at 14:44
  • Does this answer your question? [Instantiate and Present a viewController in Swift](https://stackoverflow.com/questions/24035984/instantiate-and-present-a-viewcontroller-in-swift) – Larme Feb 15 '22 at 14:44
  • No, it still crashes... I have the Storyboard linked via class... – David Feb 15 '22 at 14:54
  • @Larme, good guess on the call to LoginScreenViewController’s default initializer. You should either post that as an answer, or mark the question as a duplicate pointing to the link you posted above. – Duncan C Feb 15 '22 at 14:55
  • DO NOT USE CALLS TO `MyViewController()` (or `LoginScreenViewController()` in your case) to create your view controller from a storyboard. That won’t work. – Duncan C Feb 15 '22 at 14:56
  • @DuncanC I flagged it as a duplicate. But I don't have enough rights to close it at once, others have to flagged it also. And the wrong init without linking the storyboard/xib is the second best guess after ibtoulet not connected. – Larme Feb 15 '22 at 14:57
  • @Larme Do you have a thread that specifically says "Don't use `MyViewController()` initializer to load view controllers from a Storyboard?" That would be a better choice for a duplicate to link to. – Duncan C Feb 15 '22 at 15:04
  • Maybe https://stackoverflow.com/questions/53387373/iboutlet-nil-button – Larme Feb 15 '22 at 15:09
  • @David What's your new code with Storyboard instantiation first? Is the crash the same one? – Larme Feb 15 '22 at 15:10
  • @Larme thanks man that worked – David Feb 15 '22 at 15:35

1 Answers1

1

Edit:

This question is a case study in how not to ask a question on SO. The OP provides incomplete information, and several people engage in an extended game of 20 questions trying to figure out what's going on.

To the OP: You need to edit your question and include all the information we managed to get from you in the following comments in the original question. That's important for future readers of this thread. The question is a lot harder to follow if readers have to wade through dozens of comments to figure out the details of the question.

The cause of your crash:

You state in one of your comments that you present your view controller with the line present(LoginScreenViewController(), animated: true).

That creates an instance of LoginScreenViewController by calling its default initializer, LoginScreenViewController().

You can't do that for view controllers who's views are loaded from a storyboard. Calling the default initializer will not load the views from the Storyboard. All your outlets will be nil. The view controller's content view will be nil.

The fix:

You need to load view controllers from a storyboard by calling one of the UIStoryboard instantiate methods (like instantiateViewController(withIdentifier:).)

Also, IBOutlets are set up as "implicitly unwrapped optionals" by default. That means that when you try to reference the outlet, the compiler will silently (implicitly) try to unwrap them, and if they are nil, your code will crash.

If code that references an outlet crashes, it is likely nil. You need to go figure out why it's nil.


In your textFieldShouldReturn(_:) method, you reference both phoneAndEmailTextField and passwordTextField. They are both declared as implicitly unwrapped optionals, meaning if either of those outlets is not connected in your storyboard, that function will crash.

Try rewriting that function like this:

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    guard let phoneAndEmailTextField = phoneAndEmailTextField else {
        print("phoneAndEmailTextField is nil")
        return false
    }
    guard let passwordTextField = passwordTextField else {
        print("passwordTextField is nil")
        return false
    }

    
    phoneAndEmailTextField?.endEditing(true)
    passwordTextField?.endEditing(true)
    
    return true
}

(Note that with implicitly unwrapped optionals, if you reference them with a question mark as I did in the edited version of your function, the compiler will still do optional chaining and skip the function call/property reference if the thing being referenced is nil.)

Edit:

If it's the statement phoneAndEmailTextField.delegate = self that's crashing, that tells you that phoneAndEmailTextField is nil. You must be doing something wrong in hooking up your IBOutlets. Add a screenshot of your view controller to your question with the connections inspector shown so we can see the connections of those two outlets.

You could fix the crash by rewriting the line as phoneAndEmailTextField?.delegate = self but the phoneAndEmailTextField outlet will still be nil, so you will only be patching the problem, not fixing it.

BTW, you can connect your text field delegates to your view controller right in your storyboard. Just select the text field, pick the connections inspector, and drag from the delegate connection onto the view controller in the storyboard.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • But this doesn't resolve the issue because the Screen will never appear because of the crash. So it crashes before the screen loads... – David Feb 15 '22 at 14:12
  • See the edit to my answer. I posted it before you told us what line was crashing. When asking about a crash, alway include info about the line that's crashing your question. – Duncan C Feb 15 '22 at 14:13
  • Okay, sure forgot it. Edited with the picture of the IBOutlets. I also tried to connect directly with the delegate but this doesn't want to let me drag and drop... – David Feb 15 '22 at 14:23
  • "This question is a case study in how not to ask a question on SO" Then don't answer it. – matt Mar 02 '23 at 13:28