Extracting and managing array elements in swift - ios

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)
}

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 ""
}
}

Swift bad instruction error shopping list

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)
}

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.

Immutable value of type '[String]' only has mutating member

Getting the error of Immutable value of type '[String]' only has mutating member in my swift project and researched some answers and none seem to fix the problem in my context. Take A Look:
import UIKit
class PassionViewController: UIViewController {
var factIndex = 0
var counter = 1
#IBOutlet var QuoteImage: UIImageView!
#IBOutlet weak var funFactLabel: UILabel!
let factBook = FactBook()
let Liked = Favourite()
override func viewDidLoad() {
super.viewDidLoad()
funFactLabel.text = factBook.factsArray[factIndex]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func showFunFact() {
factIndex++
if (factIndex >= factBook.factsArray.count) {
self.factIndex = 0
}
funFactLabel.text = factBook.factsArray[factIndex]
if counter == 36 {
counter = 1
} else {
self.counter++
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
#IBAction func goBack() {
factIndex--
var number = factBook.factsArray.count-1
if (factIndex < 0){
self.factIndex = number
}
funFactLabel.text = factBook.factsArray[factIndex]
if counter == 1 {
counter = 36
} else {
self.counter--
}
QuoteImage.image = UIImage(named: "frame\(counter).jpg")
}
#IBAction func Like() {
let currentQuote = factBook.factsArray[factIndex]
Liked.favouriteArray.append(currentQuote)
}
}
The let currentQuote = factBook.factsArray[factIndex], factBook.factsArray is retrieved from another view controller which is a array collection. Liked.favouriteArray.append(currentQuote) is to store this element into favouriteArray which is from a struct called Favourite:
import Foundation
struct Favourite {
var favouriteArray:[String] = []
}
However, the line Liked.favouriteArray.append(currentQuote) is generating the error: Immutable value of type '[String]' only has mutating member. How can I resolve this error?
It's unclear because you didn't provide the Favourite type, but I assume it's either a struct, or it's a class that includes factsArray as a let variable. In either case, you're trying to modify a let variable, which is not allowed (mutating an immutable value). Either liked or factsArray must be var. (If Favourite is a struct, then liked must be var in either case.)
Note that Swift functions, methods, properties, and variables should start with a lowercase letter. Leading uppercase letters denote types.

Save score in a game with NSUserdefaults

I've made this little app "How many fingers" where the user has to guess how many fingers the computer is holding behind it's back. Now I want it to be able to save the users score with NSUserdefaults, but it's not working. Here is how my code looks right now:
//
// ViewController.swift
// How many Fingers?
//
// Created by Kevin Nguyen on 02.05.15.
// Copyright (c) 2015 Kevin Nguyen. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
#IBOutlet var userGuess: UITextField!
#IBOutlet var userScore: UILabel!
#IBOutlet var userTotal: UILabel!
#IBOutlet var result: UILabel!
var score:Int = 0
var totalGames:Int = 0
#IBAction func resetScore(sender: AnyObject) {
score = 0
userScore.text = "0"
}
#IBAction func start(sender: AnyObject) {
var userGuessInt = userGuess.text.toInt()
var fingers = Int(arc4random_uniform(6))
if userGuessInt <= 5 {
if userGuessInt == fingers {
result.text = "Great! You were right!"
score++
totalGames++
userScore.text = "\(score)"
userTotal.text = "\(totalGames)"
println("User score is \(score); total games is \(totalGames)")
NSUserDefaults.standardUserDefaults().setObject(score, forKey: "svScore")
NSUserDefaults.standardUserDefaults().setObject(totalGames, forKey: "svTotalGames")
} else {
result.text = "Try Again!"
println("User score is \(score); total games is \(totalGames)")
totalGames++
userTotal.text = "\(totalGames)"
NSUserDefaults.standardUserDefaults().setObject(score, forKey: "svScore")
NSUserDefaults.standardUserDefaults().setObject(totalGames, forKey: "svTotalGames")
}
} else{
result.text = "Enter a number from 0 up to 5!"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if score != 0 {
var score:Int = NSUserDefaults.standardUserDefaults().objectForKey("svScore")! as! Int
userScore.text = "\(score)"
}
if totalGames != 0 {
var totalGames:Int = NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames")! as! Int
userTotal.text = "\(totalGames)"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
When your application starts the score in viewDidLoad is always 0. So you'll never read the saved data (because of your if condition). You should also check it there is data stored before you try to use it.
Change it like that:
override func viewDidLoad() {
super.viewDidLoad()
if (NSUserDefaults.standardUserDefaults().objectForKey("svScore") != nil) {
score = NSUserDefaults.standardUserDefaults().objectForKey("svScore")! as! Int
}
if score != 0 {
userScore.text = "\(score)"
}
if (NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames") != nil) {
totalGames = NSUserDefaults.standardUserDefaults().objectForKey("svTotalGames")! as! Int
}
if totalGames != 0 {
userTotal.text = "\(totalGames)"
}
}
//To Save Highscore
NSUserDefaults.standardUserDefaults().setInteger(highScore, forKey: "highscore")
//To Call For Highscore
var highScore:Int = NSUserDefaults.standardUserDefaults().integerForKey("highscore")
You could create a HighscoreSaver-util class like that:
class HighscoreSaver {
private let defaults = NSUserDefaults.standardUserDefaults()
private let highscoreKey = "highscore-saver-key-item"
private var highscore:Int = 0
private func updateHighscore(score:Int){
highscore += score
if defaults.integerForKey(highscoreKey) < highscore{
defaults.setInteger(highscore, forKey: highscoreKey)
}
}
func add(score scoreToAdd:Int){
updateHighscore(scoreToAdd)
}
func reset(){
defaults.removeObjectForKey(highscoreKey)
}
func currentHighscore() -> Int{
return highscore
}
}
The usage would be like that:
var high = HighscoreSaver()
//Adds scorevalue to current score
high.add(score: yourScoreToAddToCurrent)
//Resets the score to 0
high.reset()
//Gets current score
high.currentHighscore()

Resources