Uncaught exception of type NSException - swift

I'm beginning to teach myself Swift, I am truly a beginner and I am working on a calculator app just as an intro project. I keep getting a thread error and it is terminating with an uncaught exception of type NSException. I've read in several places that this is usually caused by a missing or wrong connection from the storyboard to the view controller but I triple checked all of my connections and I don't think that is the problem. Here is my code for the view controller, is there an issue with it? I followed a tutorial for the most part.
import UIKit
extension String{
var doubleValue: Double{
if let number = NSNumberFormatter().numberFromString(self) {
return number.doubleValue
}
return 0
}
}
class ViewController: UIViewController {
var isTypingNumber = false
var firstNumber:Double? = 0
var secondNumber:Double? = 0
var operation = ""
#IBOutlet var calculatorDisplay: UILabel!
#IBAction func numberTapped(sender: AnyObject) {
var number = sender.currentTitle
if isTypingNumber {
calculatorDisplay.text = calculatorDisplay.text! + number!!
} else{
calculatorDisplay.text = number
isTypingNumber = true
}
}
#IBAction func calculationTapped(sender: AnyObject) {
isTypingNumber = false
firstNumber = calculatorDisplay.text!.doubleValue
operation = sender.currentTitle!!
}
#IBAction func equalsTapped(sender: AnyObject) {
isTypingNumber = false
var result = 0.0
secondNumber = calculatorDisplay.text!.doubleValue
if operation == "+"{
result = firstNumber! + secondNumber!
} else if operation == "-"{
result = firstNumber! - secondNumber!
} else if operation == "*"{
result = firstNumber! * secondNumber!
}
else if operation == "/"{
result = firstNumber! / secondNumber!
}
calculatorDisplay.text = "\(result)"
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I really appreciate any help I can get!

Did you happen to change the name of any IBOutlet or IBAction since first installing it into the Storyboard/xib?
Try going to your viewcontroller in Interface Builder, right-click the VC object to see all connected outlets, and check that everything's hooked up and that there aren't any dead links. (i.e. if you renamed func equalsTapped() to func equalsTapped(sender: AnyObject), the exception will be raised because equalsTapped no longer exists, instead equalsTapped: now does, and the connection is to the first.)

Related

how to init() a swift view controller properly?

I'm attempting to initialize this ViewController class. I am not using the MVC design strategy so ignore the bad conventions used (if any).
How do I initialize this class properly?
Error: 'required' initializer 'init(coder:)' must be provided by subclass of 'UIViewController'
Context: This is a calculator app that when any of the buttons are pressed. It will go find the senders title and simply put if one of the three vars are nil, it will store it in that optional.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var answerLabel: UILabel!
//global vars for all funcs
var selection1: Int? {
didSet { answerLabel.text = String(selection1!) }
}
var selection2: String? {
didSet { answerLabel.text = selection2! }
}
var selection3: Int? {
didSet { answerLabel.text = String(selection3!) }
}
var answer: Int {
didSet { answerLabel.text = String(answer) }
}
init() {
}
#IBAction func touchButton(_ sender: UIButton) {
if selection1 == nil {
selection1 = Int(sender.currentTitle!)
print("Selection set in first pos.")
} else if selection2 == nil {
selection2 = sender.currentTitle
} else if selection3 == nil {
selection3 = Int(sender.currentTitle!)
} else {
calculate(firstNum: selection1!, operation: selection2!, secondNum: selection3!)
}
}
func calculate(firstNum: Int, operation: String, secondNum: Int) {
switch operation {
case "+":
answer = firstNum + secondNum
case "-":
answer = firstNum - secondNum
case "x":
answer = firstNum * secondNum
case "/":
answer = firstNum / secondNum
default:
answerLabel.text = "Something went wrong!"
}
}
}
Initialization depends on a couple of condition.
If you are using storyboard, you can just remove the init and your VC will have default initializer. Make sure either all of your properties have default value or they are optional.
If you are using xib or just creating view programmatically you can have custom convenience initializer where you pass some extra data this way.
class MyViewController: ViewController {
var answer: Int
convenience init(answer: Int) {
self.init()
self.answer = answer
// Do other setup
}
}
Your controller is being instantiated from the storyboard. A safe place to configure initial views is during the controller's call to viewDidLoad, ie:
override func viewDidLoad() {
super.viewDidLoad()
// configure your views and subviews here
}

Swift error when I press button more times than there are pizzas in my array list

So I just started programming and I am now getting this error.
It occurs every time I press the button more times than there are Pizzas in the list.
Full error code: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0):
Here`s my code so far:
import UIKit
var pizzaNumber = 0
var pizzaNames = ["Skinke Pizza", "Salat Pizza", "Pepperoni Pizza"]
let priser = [65,70,65]
var totalProdukt = pizzaNames.count
class ViewController: UIViewController {
#IBOutlet weak var produktNavn: UILabel!
#IBAction func rightButton(_ sender: UIButton) {
pizzaNumber+=1
showPizza()
}
#IBAction func leftButton(_ sender: UIButton) {
pizzaNumber-=1
if pizzaNumber < 0 {
pizzaNumber = 0
}
showPizza()
}
func showPizza() {
if pizzaNumber > totalProdukt {
pizzaNumber = pizzaNames.count
} else {
self.produktNavn.text = pizzaNames[pizzaNumber]
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You should make sure that pizzaNumber-1 can never be bigger than the number of elements in your array to ensure that you are never trying to access an index that doesn't exist. This can be easily done by changing totalProdukt to be a computed variable. This way, the value of the variable will always be updated when you are trying to access it.
var totalProdukt: Int {
return pizzaNames.count
}
Also bear in mind that array indexing starts at 0, so you need
if pizzaNumber >= totalProdukt {
pizzaNumber = pizzaNames.count-1
} else {
self.produktNavn.text = pizzaNames[pizzaNumber]
}
Bear in mind that with your current code, there's no need for storing the count of the array in a separate variable, since you are only using it at one place in code.
Moreover, the cleanest solution is to check the value before actually increasing it rather than when using it, this way in showPizzas you don't need to do any checks, just update the label:
class ViewController: UIViewController {
#IBOutlet weak var produktNavn: UILabel!
#IBAction func rightButton(_ sender: UIButton) {
if pizzaNumber < pizzas.count-1 {
pizzaNumber+=1
}
showPizza()
}
#IBAction func leftButton(_ sender: UIButton) {
if pizzaNumber > 0 {
pizzaNumber-=1
}
showPizza()
}
func showPizza() {
self.produktNavn.text = pizzaNames[pizzaNumber]
}
}
Here's how to fix your error
func showPizza() {
if pizzaNumber >= totalProdukt { // << Added '=' since pizzaNames[pizzaNames.count] is out of bounds
pizzaNumber = pizzaNames.count - 1
} else {
self.produktNavn.text = pizzaNames[pizzaNumber]
}
}

How to set up a NSComboBox using prepare for segue or init?

I am really struggling to pass the contents of one array from a view controller to another to set up the contents of a nscombobox. I have tried everything I can think of, prepare for segue, init; but nothing seems to work.
the program flow is as follows: the user enter a number into a text field and based on it an array with the size of the number is created. Once the user presses a button the next VC appears that has a combo box and inside that combo box those numbers need to appear. All my attempts result in an empty array being passed. Could someone please take a bit of time and help me out. Im sure I'm doing a silly mistake but cannot figure out what.
Code listing below:
Class that take the user input. At this stage I'm trying to pass the contents of the array in the next class as I gave up on prepare for segue because that one crashes because of nil error. Please note that prepare for segue is uncommented in the code listing just for formatting purposes here. Im my program it is commented out as I am using perform segue at the moment.
Any solution would be nice please. Thank you.
import Cocoa
class SetNumberOfFloorsVC: NSViewController {
//MARK: - Properties
#IBOutlet internal weak var declaredNumber: NSTextField!
internal var declaredFloorsArray = [String]()
private var floorValue: Int {
get {
return Int(declaredNumber.stringValue)!
}
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction private func setNumberOfFloors(_ sender: NSButton) {
if declaredNumber.stringValue.isEmpty {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please specify the number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else if floorValue == 0 || floorValue < 0 {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please input a correct number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else {
for i in 0...floorValue - 1 {
declaredFloorsArray.append(String(i))
}
print("\(declaredFloorsArray)")
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
performSegue(withIdentifier: "set number of rooms", sender: self)
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier == "set number of rooms" {
if let addRoomsVC = segue.destinationController as? SetNumberOfRoomsForFloorVC {
addRoomsVC.floorBox.addItems(withObjectValues: declaredFloorsArray)
}
}
}
}
this is the class for the next VC with the combo box:
import Cocoa
class SetNumberOfRoomsForFloorVC: NSViewController, NSComboBoxDelegate, NSComboBoxDataSource {
//MARK: - Properties
#IBOutlet internal weak var floorBox: NSComboBox!
#IBOutlet private weak var numberOfRoomsTxtField: NSTextField!
internal var boxData = [String]()
//MARK: - Init
convenience init(boxData: [String]) {
self.init()
self.boxData = boxData
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
floorBox.usesDataSource = true
floorBox.dataSource = self
floorBox.delegate = self
print("\(boxData)")
}
#IBAction private func setRoomsForFloor(_ sender: NSButton) {
}
//MARK: - Delegates
func numberOfItems(in comboBox: NSComboBox) -> Int {
return boxData.count
}
func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
return boxData[index]
}
}
First you should remove the following code.
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
I assume you think that the viewController you created here is passed to prepareForSegue. However the storyboard instantiates a new viewController for you.
After that you need to set your declaredFloorsArray as the the boxData of the new viewController in prepareForSegue and you should be good to go.

Why won't swift recalculate the 'if' statement?

I'm trying to create a very simple 'guessing game' where the user has to guess how many fingers the computer has up (maximum 5 fingers).
Here's the thing. When the code executes and I press submit, even when the print logs registers a correct number, the app still prints the if statement for incorrect. Where am I going wrong?
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var fingerInput: UITextField!
#IBOutlet weak var fingerResult: UILabel!
#IBAction func fingerSubmit(sender: AnyObject) {
let realNumberofFingers = Int(arc4random_uniform(6))
print(realNumberofFingers)
if fingerInput != realNumberofFingers {
fingerResult.text = "Gosh darn, that's wrong!"
} else if fingerInput == realNumberofFingers {
fingerResult.text = "Thats right!"
}
}
}
You are comparing the actual UITextField fingerInput with the realNumberofFingers. That is wrong and will always yield false. What you should do instead is parse the string from the fingerInput and check if the integer contained in that string is equal to realNumberofFingers:
#IBAction func fingerSubmit(sender: AnyObject) {
let input = Int(fingerInput.text!)
if let enteredFingers = input {
let realNumberofFingers = Int(arc4random_uniform(6))
print(realNumberofFingers)
if enteredFingers == realNumberofFingers {
fingerResult.text = "Thats right!"
} else {
fingerResult.text = "Gosh darn, that's wrong!"
}
} else {
fingerResult.text = "Please enter a correct guess - an integer!"
}
}

swift unable to access contents of variable in IBAction. error: "Expected declaration"

This program compiles fine with no errors, but crashes when i click the Button attached to IBAction check Answer.
in applicationWillResignActive(_:) i see "Thread 1: signal SIGABRT"
and in my debug area, i see:
'NSInvalidArgumentException', reason: '-[Fingerz.ViewController checkAnswerButton:]: unrecognized selector sent to instance 0x7f89e254a180'
Can someone point me in the right direction towards what I am missing?
import UIKit
var num = 0
class ViewController: UIViewController
{
#IBAction func fingerGenerator(sender: AnyObject) //request random number
{
var randomNum = Int(arc4random_uniform(6))
num = randomNum
}
#IBOutlet weak var userGuess: UITextField! //user enters Guess here
#IBOutlet weak var userResult: UILabel! //display if user is right or wrong
#IBAction func checkAnswer(sender: AnyObject)
{
var userInput = userGuess.text.toInt()
println(userInput)
if num == userInput
{
userResult.text = "Great Job"
}
else
{
userResult.text = "Try again"
}
}
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The code you posted needs a closing bracket to close the class.
import UIKit
// You requested it to make this variable a global variable
var num = 0
class ViewController: UIViewController {
#IBAction func fingerGenerator(sendor: AnyObject)
{
var randomNum = Int(arc4random_uniform(6))
num = randomNum
println(num)
}
}