Swift bad instruction error shopping list - ios

I have a problem, Xcode gives me this error "EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode==0*0)" while I'm trying to make my buttons delete indexes in my array, "shoppingList".
Please help me and tell me what i did wrong so i can improve later on.
//
// ViewController.swift
// ShoppingList
//
// Created by Petr Chrastek on 29/03/16.
// Copyright © 2016 ACS. All rights reserved.
//
class ViewController: UIViewController {
#IBOutlet weak var labelText: UILabel!
#IBOutlet weak var label0: UILabel!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
var shoppingList = ["eggs", "milk", "cake", "sugar"]
#IBAction func remove0(sender: UIButton) {
shoppingList.removeAtIndex(0)
}
#IBAction func remove1(sender: UIButton) {
shoppingList.removeAtIndex(1)
}
#IBAction func remove2(sender: UIButton) {
shoppingList.removeAtIndex(2)
}
#IBAction func remove3(sender: UIButton) {
shoppingList.removeAtIndex(3)
}
override func viewDidLoad() {
super.viewDidLoad()
let str: String? = shoppingList[0]
let str1: String? = shoppingList[1]
let str2: String? = shoppingList[2]
let str3: String? = shoppingList[3]
let count = shoppingList.count
labelText.text? = "you are missing \(count) items"
if str != nil {
label0.text? = "\(str)"
} else {
label0.text? = "empty"
}
if str1 != nil {
label1.text? = "\(str1)"
} else {
label1.text? = "empty"
}
if str2 != nil {
label2.text? = "\(str2)"
} else {
label2.text? = "empty"
}
if str3 != nil {
label3.text? = "\(str3)"
} else {
label3.text? = "empty"
}
// 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.
}
}

After you delete the first item from your list, shoppingList will only have 3 items in it, so accessing shoppingList[3] will crash (remember with 3 items only 0..<2 are valid.
The easiest way to resolve the problem is to use the following pattern so you're checking the count to make sure indices are valid before using them.
if shoppingList.count > 0 {
label0.text = shoppingList[0]
} else {
label0.text = "empty"
}
if shoppingList.count > 1 {
label1.text = shopingList[1]
} else {
label1.text = "empty"
}
I've made some additional changes as well, such as not pointless using string interpolation to turn a String into the same String, since [String][n] will always return a String (never a String?) there's no need to deal with the Optionals
You'll have similar problems (in fact, probably what you're running into now) when you try to:
shoppingList.removeAtIndex(3)
the second time, since 3 is no longer a valid index, instead, use:
if shoppingList.count > 3 {
shoppingList.removeAtIndex(3)
}

Related

iOS label not start from the top

My controller allows me to show a text from a song inside a label but I don't know why the gravity of the text is focused at the end. When I want to see the text I always see the song like it's already scrolled. I want to start the song from the top and then scroll it or zoom it.
Every time I want to see a song that is longer than the page I see like it's already scrolled, but if I want to see a song that is shorter than the page it works correctly. How can I fix it??
Here is my code:
import UIKit
class DettaglioCanti: UIViewController {
var dettaglioCanzone: VociMontagna? {
didSet {
configureView()
}
}
var valoriPassati: VociMontagna?
#IBOutlet weak var tv_titolo: UILabel!
#IBOutlet weak var tv_artista: UILabel!
#IBOutlet weak var tv_testoCanzone: UITextView!
#IBAction func btt_note(_ sender: Any) {
startPopUp()
}
#IBOutlet weak var btt_note_2: UIButton!
var pinchGesture = UIPinchGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
configureView()
pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(pinchText(sender:)))
tv_testoCanzone.addGestureRecognizer(pinchGesture)
let range = NSMakeRange(tv_testoCanzone.text.count - 1, 0)
tv_testoCanzone.scrollRangeToVisible(range)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func pinchText(sender: UIPinchGestureRecognizer) {
var pointSize = tv_testoCanzone.font?.pointSize
pointSize = ((sender.velocity > 0) ? 1 : -1) * 1 + pointSize!;
//Definisco i limiti dello zoom per il testo
if (pointSize! < 13) {pointSize = 13}
if (pointSize! > 42) {pointSize = 42}
tv_testoCanzone.font = UIFont( name: "arial", size: (pointSize)!)
}
func configureView() {
if let dettaglioCanzone = dettaglioCanzone {
if let tv_titolo = tv_titolo, let tv_testoCanzone = tv_testoCanzone, let tv_artista = tv_artista {
tv_titolo.text = dettaglioCanzone.titolo
tv_artista.text = dettaglioCanzone.artista
tv_testoCanzone.text = loadFile(file: dettaglioCanzone.nomeTesto)
if (dettaglioCanzone.nomeNota == "0") {btt_note_2.isHidden = true}
}
}
}
func loadFile(file name:String) -> String {
if let path = Bundle.main.path(forResource: name, ofType: "txt") {
if let contents = try? String(contentsOfFile: path) {
return contents
} else {
print("Error! - This file doesn't contain any text.")
}
} else {
print("Error! - This file doesn't exist.")
}
return ""
}
}

Flow Control in Xcode

For some reason, even if input a valid input, namely, an integer, it does seem to go into if statement in the function, #IBAction func guess(sender: UIButton){}. In other words, if I input 5, the console output will say "Please input a valid number." Not "you guessed to high" or "you guessed to low" or "you win!". Any suggestion on how to fix this?
The following is my code:
class ViewController: UIViewController {
//just some member variables. I don't think the problem is here.
#IBOutlet weak var inputField: UITextField!
#IBOutlet weak var output: UITextView!
var guesses : UInt = 0;
var number : UInt32 = 0;
var gameover = false;
let MAX_GUESSES = 8;
var possibleGuess : Int?
override func viewDidLoad() {
super.viewDidLoad()
number = generateNewNumber()
consoleOut("I'm thinking of a number...\n")
var possibleGuess : Int? = inputField.text.toInt()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//consoleOut here prints out stuff on the app.
func consoleOut(text : String) {
output.text = output.text + text;
}
func generateNewNumber() -> UInt32 {
return arc4random_uniform(100) + 1
}
func clearInput() {
output.text = ""
}
//here lies the problem. The control never seems to go inside of
//if let guess = possibleGuess{}
#IBAction func guess(sender: UIButton) {
if let guess = possibleGuess {
if UInt32(guess) > number {
consoleOut("\(guess): You guessed to high\n")
++guesses
}
else if UInt32(guess) < number {
consoleOut("\(guess): You guessed to low\n")
++guesses
}
else {
consoleOut("\(guess): You win!\n")
consoleOut("Go again? (y/n)")
guesses = 0
gameover = true
}
clearInput()
}
else {
clearInput()
consoleOut("Please input a valid number")
}
}
}
This is a very common mistake.
You declare a variable possibleGuess as optional Int instance variable, but later you declare a variable with the same name in viewDidLoad() whose scope is locally only within the viewDidLoad() method.
Solution : delete the var keyword in the viewDidLoad() method.
possibleGuess = inputField.text.toInt()
The explicit type annotation is not needed too as the type has been already defined.

Extracting and managing array elements in swift

The main objective of this code is the ability for a user to highlight/favourite a page in application. I have an array of quotes which is scrolled through by the user on button click. I would like to have it so that when a "favourite" button is clicked (not implemented in code yet). The current element which the user is viewing is extracted (The whole string?) and then somehow marked / sent into another array. This array is then displayed using my own method. I don't know how this could be done. Here's my viewcontroller file.
import UIKit
class DreamViewController: UIViewController {
#IBOutlet var QuoteImage: UIImageView!
#IBOutlet weak var DreamLabel: UILabel!
var counter = 1
var factIndex = 0
let dreamFact = Dream()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
DreamLabel.text = dreamFact.dreamArray[factIndex]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func LeftSwipe() {
factIndex--
var number = dreamFact.dreamArray.count - 1
if (factIndex < 0){
self.factIndex = number
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 1 {
counter = 36
} else {
self.counter--
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
#IBAction func RightSwipe() {
factIndex++
if factIndex >= dreamFact.dreamArray.count {
self.factIndex = 0
}
DreamLabel.text = dreamFact.dreamArray[factIndex]
if counter == 36 {
counter = 1
} else {
self.counter++
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
}
if any additional information is required please let me now as soon as possible. Thank You!
You can use the factIndex, that you're using to track the current index, to remove the particular "quote" from the dreamArray that the user has favourited. Seeing as the factIndex is correct in tracking the current quote the user is viewing we know that we can use this to extract the right object from the array.
The suggestion below presumes that you create an Array to store your favourite quotes, such as...
var favouriteQuotesArray: [String] = []
func makeQuoteFavourite() {
let currentQuote = dreamFact.dreamArray[factIndex]
favouriteQuotesArray.append(currentQuote)
}

fatal error: unexpectedly found nil while unwrapping an Optional value Computation

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var yourScore: UITextField!
#IBOutlet weak var totalScore: UITextField!
#IBOutlet weak var labelText: UILabel!
#IBAction func buttonPressed(sender: AnyObject) {
let score1: Int = yourScore.text.toInt()!
let score2: Int = totalScore.text.toInt()!
let mistakes = score2 - score1
let scoreFinal = ((((score2 / 2) - mistakes)*23)/score2)+75
labelText.text = "\(scoreFinal)"
}
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.
}
}
Something is wrong with my code. Is it because of data types or something? When I load the application, it just opens fine but when the button is pressed, the app crashes.
http://i.stack.imgur.com/B2i5Z.png
You could safely unwrap the values with if let:
if let score1 = yourScore.text.toInt() {
if let score2 = totalScore.text.toInt() {
let mistakes = score2 - score1
let scoreFinal = ((((score2 / 2) - mistakes)*23)/score2)+75
labelText.text = "\(scoreFinal)"
} else {
// no valid score2
}
} else {
// no valid score1
}
While unwrapping, you can't just willy nilly use the values. Before unwrapping you have to check if the current value is nil. If it's not nil, then you can safely unwrap the text.

swift accessing variable from another file

I am a newbie swift programmer, and I have been asked to write an app that allows you to type in a word, and then generates a random Haiku
This is a tabbed application, with two ViewControllers.
(poem) based on that word. So in the FirstViewController I have the data, and I want to display that data in a nice way, in the SecondViewController.
I have all the poem lines and all in the FirstViewController, but I would like to access these variables in the SecondViewController. I have tried creating a function, that does nothing but returning them, and then in the SecondViewController calling that function, but without any result, since the function simply returned nil. Would be pleased if any of you could help
Thank you!
Here is the FirstViewController:
import UIKit
import Foundation
class FirstViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var keyWordTextField: UITextField!
#IBOutlet weak var syllableSlider: UISlider!
#IBOutlet weak var syllableSliderLabel: UILabel!
var syllableSliderValue = 1
#IBOutlet weak var lineOneTextField: UITextField!
#IBOutlet weak var lineTwoTextField: UITextField!
#IBOutlet weak var lineThreeTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
lineOneTextField.text = "Rad 1"
lineTwoTextField.text = "Rad 2"
lineThreeTextField.text = "Rad 3"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func syllableValueChanged(sender: UISlider) {
syllableSliderValue = Int((sender.value))
syllableSliderLabel.text = "Ordet har: \(syllableSliderValue) stavelser"
}
#IBAction func getNewHaiku() {
if keyWordTextField.text != "" {
let keyWord = keyWordTextField.text
let lineOne = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 5)
let lineTwo = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 7)
let lineThree = generateLine(keyWord: keyWord, syllables: syllableSliderValue, lineSyllableLenght: 5)
lineOneTextField.text! = lineOne
lineTwoTextField.text! = lineTwo
lineThreeTextField.text! = lineThree
}
}
func generateLine(#keyWord: String, syllables : Int, lineSyllableLenght : Int) -> String {
let oneSyllables = Dict().oneSyllables
let twoSyllables = Dict().twoSyllables
let threeSyllables = Dict().threeSyllables
let fourSyllables = Dict().fourSyllables
let randomOneSyllableWordNumber = Int(arc4random_uniform(UInt32(oneSyllables.count)))
let randomTwoSyllableWordNumber = Int(arc4random_uniform(UInt32(twoSyllables.count)))
let randomThreeSyllableWordNumber = Int(arc4random_uniform(UInt32(threeSyllables.count)))
let randomFourSyllableWordNumber = Int(arc4random_uniform(UInt32(fourSyllables.count)))
var lineArray : [String] = []
var line = ""
lineArray.append(keyWord)
if syllables == 1 {
let randomWordMethod = Int(arc4random_uniform(2))
if randomWordMethod == 0 {
lineArray.append(fourSyllables[randomFourSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(threeSyllables[randomThreeSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
} else if randomWordMethod == 2 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(twoSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 2 {
let randomWordMethod = Int(arc4random_uniform(2))
if randomWordMethod == 0 {
lineArray.append(twoSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomTwoSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(threeSyllables[randomThreeSyllableWordNumber])
} else if randomWordMethod == 2 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 3 {
let randomWordMethod = Int(arc4random_uniform(1))
if randomWordMethod == 0 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
} else if syllables == 4 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
}
if lineSyllableLenght == 7 {
let randomWordMethod = Int(arc4random_uniform(1))
if randomWordMethod == 0 {
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
lineArray.append(oneSyllables[randomOneSyllableWordNumber])
} else if randomWordMethod == 1 {
lineArray.append(twoSyllables[randomTwoSyllableWordNumber])
}
}
for word in lineArray {
line += " \(word)"
}
line += ","
return line
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func getData() -> (line2: String, line3: String) {
return (lineTwoTextField.text, lineThreeTextField.text)
}
}
Ps, the "Dict" is another file, but only containing words.
The second view controller is just blank.
Or you could make it a global variable so any file can access it.
struct structname {
static var yourvariable = value
}
When calling it, you enter
filename.structname.yourvariable
You need to pass the instances like this in second view controller:
var firstViewController: FirstViewController?
Then in the master instance which knows both:
secondViewController.firstViewController = firstViewController
(e.g. in awakeFromNib) assuming that they are known in the master instance like
let firstViewController = FirstViewController()
let secondViewController = SecondViewController()
Finally in SecondViewController you can access the first:
firstViewController?.generateLine....

Resources