Swift 3 - Add user input to array and pick random item - arrays

The idea of this app is that the user types in something then clicks submit and the text field empties so they can type in something else then when they click a different button called randomised a label's text turns into a random item from the items the user entered. I thought I should append new inputs to an array and then create a randomIndex and then make the label's text a random item from the array using the randomIndex. Here's my code:
var choices = [""]
#IBOutlet weak var chosenLabel: UILabel!
#IBAction func randomiseButton(_ sender: Any) {
let randomIndex = Int(arc4random_uniform(UInt32(self.choices.count)))
let randomItem = self.choices[randomIndex]
self.chosenLabel.text = "\(randomItem)"
}
#IBOutlet weak var enterLabel: UITextField!
#IBAction func submitButton(_ sender: Any) {
let newItem = self.enterLabel.text
self.choices.append(newItem!)
self.enterLabel.text = ""
}
Thanks for all help in advance. Btw this doesn't bring up an error or anything but when I run this app on my iPad and enter things it works fine until I click randomise and then nothing happens. :(

Ok, so this is quite embarrassing. I tried out other people's comments and none were working. #pdil said, "Is the randomise button properly connected to the IBAction?". I added a print function into that button and nothing was working so I knew the connection was wrong. It turned out I had my button hooked up to a label. I will put here the code I used in the end:
var choices = [String]()
#IBOutlet weak var chosenLabel: UILabel!
#IBAction func randomiseButton(_ sender: Any) {
let randomIndex = Int(arc4random_uniform(UInt32(self.choices.count)))
let randomItem = self.choices[randomIndex]
self.chosenLabel.text = "\(randomItem)"
print("testing")
}
#IBOutlet weak var enterLabel: UITextField!
#IBAction func submitButton(_ sender: Any) {
let newItem = self.enterLabel.text
self.choices.append(newItem!)
self.enterLabel.text = ""
}
Sorry about this and thanks for all your help :)

Related

Swift - User Defaults not loading array of strings when app is launched

So I have an app for a Midwestern car game where you count cows when you're driving and when you see a cemetery you lose half your cows. Whenever someone sees a cemetery, I have an emoji appear as an appended array of string, so they keep adding up. My problem is I can save the array to user defaults and it will print it correctly, but whenever I relaunch the app, the array goes back to a blank array of strings. So I know the data is saved correctly, just not loading when the app launches.
class ViewController: UIViewController {
#IBOutlet weak var playerOneNameText: UITextField!
#IBOutlet weak var numberOfCowsPlayerOne: UILabel!
#IBOutlet weak var playerOneCows: UILabel!
#IBOutlet weak var playerOneCemeteries: UILabel!
let userDefaults = UserDefaults.standard
var cemeteryEmoji: [String] = UserDefaults.standard.object(forKey: "CemeteryEmoji")! as? [String] ?? []
It will also strangely load the correct array in the field for display, but will start over any time a new cemetery is added:
override func viewDidLoad() {
super.viewDidLoad()
if userDefaults.value(forKey: "CemeteryEmoji") != nil{
playerOneCemeteries.text = "\(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)"
print(cemeteryEmoji)
}else {
playerOneCemeteries.text = ""
}
}
And here's the function for all the cemetery data:
#IBAction func playerOneCemetery(_ sender: UIButton) {
let cemeteryCows = UserDefaults.standard.integer(forKey: "TotalCows") / 2
self.userDefaults.set(cemeteryCows, forKey: "TotalCows")
print(cemeteryCows)
self.numberOfCowsPlayerOne.text = "\(self.userDefaults.string(forKey: "TotalCows")!) cows"
addCemeteryEmoji()
print(UserDefaults.standard.object(forKey: "CemeteryEmoji")!)
func addCemeteryEmoji() {
cemeteryEmoji.append("🪦")
print(cemeteryEmoji)
self.playerOneCemeteries.text = "\(cemeteryEmoji.joined())"
userDefaults.set(cemeteryEmoji.joined(), forKey: "CemeteryEmoji")
}
}
So I'm not sure if it's an issue simply when the app loads or if I need to save it a different way (although as I said, that works perfectly fine with all the print statements). Any help would be great.
The error occurs because you join the array right before saving it which creates a single string.
And when you relaunch the app object(forKey: "CemeteryEmoji")! as? [String] fails.
I highly recommend to name the array more meaningful and use the dedicated API array(forKey:).
Name the array in plural form and declare an empty array
var cemeteryEmojis = [String]()
In viewDidLoad load the array from UserDefaults
override func viewDidLoad() {
super.viewDidLoad()
if let emojis = userDefaults.array(forKey: "CemeteryEmoji") as? [String] {
playerOneCemeteries.text = "\(emojis.joined())"
cemeteryEmojis = emojis
print(cemeteryEmojis)
} else {
playerOneCemeteries.text = ""
}
}
And delete joined() in the set line of addCemeteryEmoji
func addCemeteryEmoji() {
cemeteryEmojis.append("🪦")
print(cemeteryEmojis)
self.playerOneCemeteries.text = "\(cemeteryEmojis.joined())"
userDefaults.set(cemeteryEmojis, forKey: "CemeteryEmoji")
}

Random data transfer to button in Swift. (Array)

import UIKit
class ViewController: UIViewController {
var buttonArray = [String] ()
#IBOutlet weak var button3: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button1: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
buttonArray.append("answer1")
buttonArray.append("answer2")
buttonArray.append("answer3")
}
#IBAction func buttonClick(_ sender: UIButton) {
while true {
let randomArray = buttonArray[Int.random(in: 0...2)]
button1.titleLabel?.text = randomArray
break
}
}
}
I want to create a test. This test will have 3 answer choices and these answers will be randomly assigned to the buttons. I don't want an answer to be assigned to two choices. for this, I want to take the first assigned option into the array and remove it from the array after it is assigned. i don't understand how i can do this
You can remove an item at a random index. This item is returned from remove(at:
let randomElement = buttonArray.remove(at: Int.random(in: 0..<buttonArray.count)]
button1.titleLabel?.text = randomElement
Side note: Never hard-code array indices for a range.
To assign all three values randomly to the three buttons shuffle the array
let shuffledArray = buttonArray.shuffled()
button1.titleLabel?.text = shuffledArray[0]
button2.titleLabel?.text = shuffledArray[1]
button3.titleLabel?.text = shuffledArray[2]

Multiple Switches in an Array are activated when only one is pressed Swift

I am working on an attendance app that uploads and stores all of its data in firebase. Most things are currently working except that sometimes when a switch is pressed in the array of students in the club, 2 of the switches activate in the array but the information normally sent when a switch is pressed is only sent for the switch that I actually pressed.
Here is the TableView cell code:
import UIKit
import Firebase
class StudentCell: UITableViewCell {
var student: Student? { didSet { self.updateUI() }}
#IBOutlet weak var lblStudentName: UILabel!
#IBOutlet weak var lblStudentId: UILabel!
#IBOutlet weak var lblStudentAttending: UISwitch!
let ref = Database.database().reference()
var user: Student! {
didSet{
lblStudentName.text = user.FullName()
lblStudentId.text = user.StudentId
lblStudentAttending.isOn = false
}
}
var switchReference: DatabaseReference?
var switchHandle: DatabaseHandle?
func stopObservation() {
if let handle = switchHandle {
switchReference?.removeObserver(withHandle: handle)
}
}
func startObservation() {
stopObservation()
if let uid = student?.StudentId {
switchReference = ref.child("attendance").child(Global.shared.currentDate).child(uid)
switchReference?.observe(.value, with: { [weak self] (snapshot: DataSnapshot) in
DispatchQueue.main.async {
let isOn = (snapshot.value as? Bool) ?? false
self?.lblStudentAttending.isOn = isOn
}
})
}
}
func updateUI() {
startObservation()
self.lblStudentName.text = self.student?.FullName() ?? ""
self.lblStudentId.text = self.student?.StudentId ?? ""
}
#IBAction func `switch`(_ sender: UISwitch) {
switchReference?.setValue(sender.isOn)
}
}
Does anyone know why this might be happening? If you need more information lmk. TIA -Ben
Does anyone know why this might be happening?
Tables reuse their cells so that they don't have to keep allocating new ones, which is expensive when the user is trying to scroll through a lot of rows quickly. You're setting up an observer for the switch in each cell, which means that you need to stop observing that switch when the cell is no longer visible. You could probably call stopObservation() in the cell's prepareForReuse() method and solve the problem.
A better solution would be to avoid observing the switch altogether, and instead use the target/action mechanism that controls typically use to trigger an action when the user changes their value. That way you don't have to worry about constantly starting and stopping observation.

Setting UILabel Text to a Variable Not Outputting Correctly

I am trying to create a quick test system to make an array and display it. Text is inputted into the text field, and when the button is pressed, the text is added to the array, and the output text is updated. However, if I want to add the data "Sandwich" to the array, it outputs in the label as 'Optional("Sandwich")'. I have already tried using the ? and ! to get it out, but nothing seems to work. Would anyone know how to fix this?
#IBOutlet weak var dataEntryTextField: UITextField!
#IBOutlet weak var addDataButton: UIButton!
#IBOutlet weak var addDataLabel: UILabel!
#IBOutlet weak var dataOutput: UILabel!
var List = [""]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.dataEntryTextField.text = ""
self.dataOutput.text = ""
dataOutput.sizeToFit()
//Add more attributes here
//Apply to the label
dataOutput.backgroundColor = UIColor.grayColor()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldReturn(TextField: UITextField) -> Bool
{
dataEntryTextField.resignFirstResponder()
return true;
}
#IBAction func addData(sender: UIButton) {
if self.dataEntryTextField.text == "" {}
else {
if List == [""] {List[0] = "• \(self.dataEntryTextField.text)"}
else {List.append("• \(self.dataEntryTextField.text)")}
self.dataOutput.text = List.joinWithSeparator(" ")
}
self.dataEntryTextField.text = ""
dataEntryTextField.resignFirstResponder()
}
You will have to use optional binding to unwrap your optional value. Assume you have an optional text,
var text: String? = "Sandwich"
print("\(text)") // This would print "Optional("Sandwich")"
When its unwrapped using optional binding, you will get the actual text provided the value is not nil.
if let unwrappedText = text {
print("\(unwrappedText)") // This will print "Sandwich"
}
Refer to this link to understand Optionals.
In your code, you will have to unwrap your self.dataEntryTextField.text value and append it to list.

Showing array content on a button, using a label

I have searched around but have not found an answer. It may be simple but I can nor figure out how you are suposed to do it. So...
I want a button to show an array on a label. When I press the first time, the label show the first number in the array, an pressing a second time makes the label print the second number in the array.
var primeString = ["60","52","81","61","85"]
#IBOutlet var PrimeLabel: UILabel!
#IBAction func NewAction(sender: AnyObject) {
// Here is where I want to make the label show the array in the order when I press it.
}
Declare a variable count and initialise to 0
var primeString = ["60","52","81","61","85"]
var count = 0
#IBOutlet var PrimeLabel: UILabel!
And then action for Button Click.
#IBAction func NewAction(sender: AnyObject) {
PrimeLabel.text = primeString[count%primeString.count]
count++
}
So just to get this straight. Each time you press the button you want to display the next element in the array through the label. Okay, that should be fairly simple. Something like below will do that for you.
var primeString = ["60","52","81","61","85"]
var currentElement = 0
#IBOutlet var PrimeLabel: UILabel!
#IBAction func NewAction(sender: AnyObject) {
if currentElement < primeString.count {
PrimeLabel.text = primeString[currentElement]
currentElement++
} else {
print("No more elements to display.")
}
}
No need to have the view did load, as we don't need to do any setup once the view has loaded. I hope this helps you out.
Why don't you use Generator for this?
E.g. something like:
var primeStringGenerator = ["60","52","81","61","85"].generate()
#IBOutlet var PrimeLabel: UILabel!
#IBAction func NewAction(sender: AnyObject) {
PrimeLabel.text = primeGenerator.next() ?? "n/a"
}
var primeString = ["60","52","81","61","85"]
#IBOutlet var PrimeLabel: UILabel!
var number = 0
#IBAction func NewAction(sender: AnyObject) {
PrimeLabel.text = primeString[i]
i++
}

Resources