Pass Full Array between view controllers in swift - arrays

I am trying to pass a full array between view controllers but cannot figure out the missing piece.
In view controller one I have:
protocol ExclusionsViewViewControllerDelegate{
func ExcUpperDidFinish(controller:ExclusionsView)
func ExcLowerDidFinish(controller:ExclusionsView)
}
class ExclusionsView: UIViewController, UITableViewDataSource, UITableViewDelegate {
var delegate:ExclusionsViewViewControllerDelegate? = nil
var ExcLowerArray:[Int]=[]
var ExcUpperArray:[Int]=[]
#IBOutlet var ExcLowerText: UITextField!
#IBOutlet var ExcUpperText: UITextField!
#IBOutlet var ExcFreqTable: UITableView!
#IBAction func BackButton(sender: AnyObject) {
if (delegate != nil){
delegate!.ExcUpperDidFinish(self, Array: ExcUpperArray)
delegate!.ExcLowerDidFinish(self, Array: ExcLowerArray)
}
dismissViewControllerAnimated(true,completion:nil)
}
In View controller two I have:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, PreferencesViewControllerDelegate, ExclusionsViewViewControllerDelegate {
var ExcUpperFreqArray:[Int]=[]
var ExcLowerFreqArray:[Int]=[]
override func viewDidLoad() {
super.viewDidLoad()
}
func ExcLowerDidFinish(controller: ExclusionsView, Array:[Int]) {
ExcLowerFreqArray = Array
controller.navigationController?.popViewControllerAnimated(true)
}
func ExcUpperDidFinish(controller: ExclusionsView, Array:[Int]) {
ExcUpperFreqArray = Array
controller.navigationController?.popViewControllerAnimated(true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "pushExclusions"{
let zc = segue.destinationViewController as ExclusionsView
zc.ExcLowerArray = ExcLowerFreqArray
zc.ExcUpperArray = ExcUpperFreqArray
}
}
I cannot figure out how to correctly reference the array. I am trying to create the array ExcLowerArray in view controller one, and when I change view it will copy all data to the array ExcLowerFreqArray in the second view controller, so that I can reference it in that view controller. At the moment though I get an error on these two lines:
delegate!.ExcLowerDidFinish(self, Array: ExcLowerArray)
func ExcLowerDidFinish(controller: ExclusionsView, Array:[Int]) {

Swift arrays are value types, and as such they are passed not by reference but by value, which means a copy is created when an array is passed to a function, assigned to a variable, etc.
In order to pass an array (and more generally any value type) to a function by reference, you can use the inout modifier in the function declaration, and use the reference operator & when passing the argument to the function. In your case:
func ExcLowerDidFinish(controller: String, inout Array:[Int])
and:
delegate!.ExcLowerDidFinish(self, Array: &ExcUpperArray)
Off topic: note that by convention in swift functions/methods and variables/parameters names start with lowercase, whereas types (classes, structs, etc.) start with uppercase. Your code may be hard to read by other Swift developers

Related

Why does the console print out the Name of my App/Module?

im currently building an app where you can choose a time and save this data. I built a struct with called Session with this time as an property. When the user save the data i want this new session to be appended to an array of sessions. However when i print out the array there is always the name of my XCode project in front of the struct inside they array, kind of like a path. Do you know how i can fix this, or how i can remove the module name in front of the initialized struct ?
Heres a picture of my console:
Heres my code:
struct Session {
let chosenTime: Int
}
class FirstViewController: UIViewController {
#IBOutlet weak var fiveMinButton: UIButton!
#IBOutlet weak var tenMinButton: UIButton!
#IBOutlet weak var saveDataButton: UIButton!
var sessions: [Session] = []
var selectedTime: Int = 0
#IBAction func timeButtonPressed(_ sender: UIButton) {
selectedTime = sender.tag
print(selectedTime)
}
#IBAction func saveDataPressed(_ sender: UIButton) {
let newSession = Session(chosenTime: selectedTime)
sessions.append(newSession)
print(sessions)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

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]

Segue textfields to a string array

I'm doing an app using swift that takes the entries in 6 text fields and passes them through a segue into an empty string array on a second view controller. How do I do that?
This is my code, is the basics, but I'm not sure how I can send the information through.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as! secondView
if segue.identifier == segueID {
destination.stringArray = ?
}
}
The array on my second view controller is this:
var stringArray = [String]()
The shortest way:
destination.stringArray = view.subviews.flatMap { ($0 as? UITextField)?.text }
Are your 6 textfields in an IBOutletCollection (in other words, an array of textfields) or are they each their own IBOutlet (textfield)? Either way, your question comes down to putting all of their text values in an array, which can be done like this if they're in an IBOutletCollection:
destination.stringArray = myTextFieldCollection.flatMap { $0.text }
Or, if they're not in an array:
destination.stringArray = [myTextField1, myTextField2, ...,
myTextField6].flatMap { $0.text }
I'm using flatMap in these because UITextField.text is an optional String?, so they need to be unwrapped to String, which flatMap safely does.

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.

Resources