signal SIGABRT ('NSUnknownKeyException') error when trying to run Xcode 10.3 app [Not using Storyboards]

165 Views Asked by At

.xib file (Interface), Show the Identity Inspector Tab I am new to Xcode and Swift, and was trying to run a simple multiplication game app. However, when I try to run a test on the simulator, I receive a SIGABRT signal error, and the app does not load. I am not sure how to approach this, please help! I have tries everything and nothing seems to work. Note: I am not using storyboards, and have deleted the main.storyboard file from the project folder, focusing on the xib file (I am using Xcode 10.3)

The Error I receive is:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key inputField.'

// This is my AppDelegate. I receive the SIGABRT signal on the third line (class AppDelegate). 


import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var mainVC: MainViewController?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        mainVC = MainViewController(nibName: "MainViewController", bundle:nil)

        let frame = UIScreen.main.bounds
        window = UIWindow(frame:frame)

        window!.rootViewController = mainVC
        window!.makeKeyAndVisible()

        return true
    }

}

Separate file

//MainViewController.swift, created with MainViewController.xib

import UIKit

class MainViewController: UIViewController
{   
@IBOutlet weak var number1:UILabel?
@IBOutlet weak var number2:UILabel?
@IBOutlet weak var timeLabel:UILabel?
@IBOutlet weak var scorecounter:UILabel?
@IBOutlet weak var inputField:UITextField?

var score:Int = 0
var timer:Timer?
var seconds:Int = 60

override func viewDidLoad()
{
    super.viewDidLoad()
    setRandomNumberLabel1()
    setRandomNumberLabel2()
    updateScoreLabel()

    inputField?.addTarget(self, action: #selector(textFieldDidChange(textField:)), for:UIControl.Event.editingChanged)
}

func updateScoreLabel()
{
    scorecounter?.text = "\(score)"
}

func updateTimeLabel()
{
    if(timeLabel != nil)
    {
        let min:Int = (seconds / 60) % 60
        let sec:Int = seconds % 60

        let min_p:String = String(format: "%02d", min)
        let sec_p:String = String(format: "%02d", sec)

        timeLabel!.text = "\(min_p):\(sec_p)"
    }
}

func setRandomNumberLabel1()
{
    number1?.text = generateRandomString()
}

func setRandomNumberLabel2()
{
    number2?.text = generateRandomString()
}

@objc func textFieldDidChange(textField:UITextField)
{
    if inputField?.text?.count ?? 0 < 1
    {
        return
    }

    if  let number1_text    = number1?.text,
        let number2_text    = number2?.text,
        let input_text      = inputField?.text,
        let number1 = Int(number1_text),
        let number2 = Int(number2_text),
        let input   = Int(input_text)
    {
        print("Comparing: \(input_text) == \(number1_text) times \(number2_text)")

        if(input == number1 * number2)
        {
            print("Correct!")

            score += 1
        }
        else
        {
            print("Incorrect!")

            score -= 1
        }
    }

    setRandomNumberLabel1()
    setRandomNumberLabel2()
    updateScoreLabel()
    updateTimeLabel()

    if(timer == nil)
    {
        timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector:#selector(onUpdateTimer), userInfo:nil, repeats:true)
    }
}

@objc func onUpdateTimer() -> Void
{
    if(seconds > 0 && seconds <= 60)
    {
        seconds -= 1

        updateTimeLabel()
    }
    else if(seconds == 0)
    {
        if(timer != nil)
        {
            timer!.invalidate()
            timer = nil

            let alertController = UIAlertController(title: "Game Over!", message: "Time's up! You got a score of: \(score) points. Good Job!", preferredStyle: .alert)

            let restartAction = UIAlertAction(title: "Restart", style: .default, handler: nil)
            alertController.addAction(restartAction)

            self.present(alertController, animated: true, completion: nil)

            score = 0
            seconds = 60

            updateTimeLabel()
            updateScoreLabel()
            setRandomNumberLabel1()
            setRandomNumberLabel2()
        }
    }
}

override func didReceiveMemoryWarning()
{
    super.didReceiveMemoryWarning()
}

func generateRandomString() -> String
{
    var result:String = ""

    for _ in 1...1
    {
        let digit = Int.random(in: 1..<10)

        result += "\(digit)"
    }

    return result
}
}
1

There are 1 best solutions below

5
On

Change your outlets to be non-optional:

@IBOutlet weak var number1: UILabel!
@IBOutlet weak var number2: UILabel!
@IBOutlet weak var timeLabel: UILabel!
@IBOutlet weak var scorecounter: UILabel!
@IBOutlet weak var inputField: UITextField!
  1. Open your viewController in your Storyboard and select your controller:

enter image description here

  1. Check the menu on the right. It should have changed to have the last icon, an arrow, selected. Your outlets should be there:

enter image description here

  1. Connect your outlets to each element on the view. You can do this by clicking on the empty radio button on each element and dragging the cursor:

enter image description here

  1. Build and run the project again.

If by any chance you can't see the outlets in step 2, you might have a wrong reference to your class. After step 1, click on the middle button on the right menu:

enter image description here

If the class field doesn't match your controller, change to it. Based in your code, yours should be MainViewController. Set that and go back to step 2.