I'm currently trying to connect two UISegmentedControls where the first Viewcontroller is connected to the second. Tapping the second UISegment will update the value of the first one.
ViewController:
class ViewController: UIViewController {
#IBOutlet weak var tipLabel: UILabel!
#IBOutlet weak var totalLabel: UILabel!
#IBOutlet weak var billField: UITextField!
#IBOutlet weak var tipController: UISegmentedControl!
#IBOutlet weak var splitController: UISegmentedControl!
#IBOutlet weak var splitLabel: UILabel!
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
defaults.synchronize()
billField.becomeFirstResponder()
tipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
print(tipController.selectedSegmentIndex)
// 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.
}
// #IBAction func toSettings(_ sender: Any) {
// self.performSegue(withIdentifier: "toSettings", sender: self)
// }
#IBAction func onTap(_ sender: Any) {
view.endEditing(true)
}
#IBAction func calculateTip(_ sender: Any) {
let tipPercentages = [0.18, 0.20, 0.25]
let splitNumbers = [1,2,3,4]
let bill = Double(billField.text!) ?? 0
let tip = bill * tipPercentages[tipController.selectedSegmentIndex]
let total = bill + tip
tipLabel.text = String(format: "$%.2f", tip)
totalLabel.text = String(format: "$%.2f", total)
splitLabel.text = String(format: "$%.2f", total/Double((splitNumbers[splitController.selectedSegmentIndex])))
}
SettingViewController:
class SettingsViewController: UIViewController {
var tipPercentageIndex:Int!
#IBOutlet weak var settingsTipController: UISegmentedControl!
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
settingsTipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
// Do any additional setup after loading the view.
}
#IBAction func Index(_ sender: Any) {
tipPercentageIndex = settingsTipController.selectedSegmentIndex
}
#IBAction func saveButton(_ sender: Any) {
tipPercentageIndex = settingsTipController.selectedSegmentIndex
defaults.set(tipPercentageIndex, forKey: "default_tip_index")
defaults.synchronize()
self.performSegue(withIdentifier: "Tippy", sender: self)
}
#IBAction func Back(_ sender: Any) {
self.performSegue(withIdentifier: "Tippy2", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
However, my solution does not update the value nor store the value when switching back from the second to the first.
Note: the first segues to the second.
Add an IBAction for Value Changed for the segmented controls, and update values for the affected controls:
func updateSegments(){
if let value = UserDefaults.standard.value(forKey: "key"){
let selectedIndex = value as! Int
yourSegmentedControl.selectedSegmentIndex = selectedIndex
} else {
yourSegmentedControl.selectedSegmentIndex = 0 // set to default
}
if let value = UserDefaults.standard.value(forKey: "anotherkey"){
let selectedIndex = value as! Int
anotherSegmentedControl.selectedSegmentIndex = selectedIndex
} else {
anotherSegmentedControl.selectedSegmentIndex = 0 // set to default
}
//etc...
}
#IBAction func yourSegmentedControlSelected(_ sender: UISegmentedControl) {
UserDefaults.standard.set(sender.selectedSegmentIndex, forKey: "key")
self.updateSegments()
}
#IBAction func anotherSegmentedControlSelected(_ sender: UISegmentedControl) {
UserDefaults.standard.set(sender.selectedSegmentIndex, forKey: "anotherkey")
self.updateSegments()
}
From how you've explained your code, I think your problem is that the code that loads your dependent values, is only called when your viewController is loaded. And I believe, the viewController you are "switching back" to, has already been loaded. So the set up code will not be executed again after updating your defaults.
One quick fix to try is moving your set up code for viewDidLoad to viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
defaults.synchronize()
billField.becomeFirstResponder()
tipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
print(tipController.selectedSegmentIndex)
}
Update
Just noticed you said the value is not stored, along with my pervious suggestion try this—
Create a method that sets the defaults to the settingsTipController.selectedSegmentIndex. When you load the SettingsViewController, add the method as a target to the settingsTipController that acts on a .valueChanged event.
When save is tapped the last selected value will be saved.
In SettingsViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
settingsTipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
settingsTipController.addTarget(nil, action: #selector(didToggleSwitch), for: .valueChanged)
}
#objc func didToggleSwitch() {
tipPercentageIndex = settingsTipController.selectedSegmentIndex
defaults.set(tipPercentageIndex, forKey: "default_tip_index")
}
#IBAction func saveButton(_ sender: Any) {
tipPercentageIndex = settingsTipController.selectedSegmentIndex
defaults.set(tipPercentageIndex, forKey: "default_tip_index")
defaults.synchronize()
self.performSegue(withIdentifier: "Tippy", sender: self)
}
Related
I have mainVC with 4 labels and 4 goToVC buttons, each button use segue to present another 1 of 4 VC. Every vc have textField and doneButton. I want to show text from textField in mainVC labels and i want to use delegates. But instead i got empty labels. Please help.
Delegate.swift
protocol TextFieldDelegate {
func didFinishTextField(text: String)
}
MainVC.swift
class MainViewController: UIViewController, TextFieldDelegate {
#IBOutlet weak var redText: UILabel!
#IBOutlet weak var orangeText: UILabel!
#IBOutlet weak var pinkText: UILabel!
#IBOutlet weak var purpleText: UILabel!
var choosenLabel: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toRedVC" {
let vc = segue.destination as! RedViewController
vc.delegate = self
choosenLabel = redText
} else if segue.identifier == "toOrangeVC" {
let vc = segue.destination as! OrangeViewController
vc.delegate = self
choosenLabel = orangeText
} else if segue.identifier == "toPinkVC" {
let vc = segue.destination as! PinkViewController
vc.delegate = self
choosenLabel = pinkText
} else if segue.identifier == "toPurpleVC" {
let vc = segue.destination as! PurpleViewController
vc.delegate = self
choosenLabel = purpleText
}
}
func didFinishTextField(text: String) {
if let data = choosenLabel {
data.text = text
}
}
#IBAction func redButton(_ sender: UIButton) {
}
#IBAction func orangeButton(_ sender: UIButton) {
}
#IBAction func pinkButton(_ sender: UIButton) {
}
#IBAction func purpleButton(_ sender: UIButton) {
}
}
RedVC(other 3 same).swift
class RedViewController: UIViewController {
var delegate: TextFieldDelegate?
var textVar: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func textField(_ sender: UITextField) {
if let data = sender.text {
textVar = data
}
}
#IBAction func doneButton(_ sender: UIButton) {
delegate?.didFinishTextField(text: textVar)
dismiss(animated: true, completion: nil)
}
}
Everything seems ok in your code. I suggest you to check your text field's actions are set to editingChanged in ViewController.
I would like to know how i could do a switch-case/any good statement for user defaults instead of using if-else because as you can see from my code, i'm using 3 if statements which is abit redundant and ugly.
The purpose of this view controller is for a "Pick a card" game, the user gets to pick 3 cards each time and if he/she selects a card, they will not be able to select that particular card again.
import UIKit
class ViewController: UIViewController {
#IBOutlet var buttona: UIButton!
#IBOutlet var buttonb: UIButton!
#IBOutlet var buttonc: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
if (UserDefaults.standard.integer(forKey: "dissapear") == 1)
{
buttona.setImage(UIImage(named: "wildcardbackingblack.png"), for: .normal)
buttona.isEnabled = false
}
if (UserDefaults.standard.integer(forKey: "dissapear2") == 1)
{
buttonb.setImage(UIImage(named: "wildcardbackingblack.png"), for: .normal)
buttonb.isEnabled = false
}
if (UserDefaults.standard.integer(forKey: "dissapear3") == 1)
{
buttonc.setImage(UIImage(named: "wildcardbackingblack.png"), for: .normal)
buttonc.isEnabled = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Button1(_ sender: Any) {
UserDefaults.standard.set(1, forKey:"dissapear")
self.performSegue(withIdentifier: "show", sender: nil)
}
#IBAction func Button2(_ sender: Any) {
UserDefaults.standard.set(1, forKey:"dissapear2")
self.performSegue(withIdentifier: "show", sender: nil)
}
#IBAction func Button3(_ sender: Any) {
UserDefaults.standard.set(1, forKey:"dissapear3")
self.performSegue(withIdentifier: "show", sender: nil)
}
}
func updateCard(button: UIButton, image: String, isEnabled: Bool) {
DispatchQueue.main.asyc {
button.setImage(UIImage(named:image), for: .normal)
button.isEnabled = isEnabled
}
}
.
.
.
let option : Int = UserDefaults.standard.integer(forKey: "dissapear")
switch (option) {
case 1:
self.updateCard(button: ..., image:"wildcardbackingblack.png", isEnabled: false)
case 2:
self.updateCard(button: ..., image:"wildcardbackingblack.png", isEnabled: false)
case 3:
self.updateCard(button: ..., image:"wildcardbackingblack.png", isEnabled: false)
default:
self.updateCard(button: ..., image:"default.png", isEnabled: false)
}
//Save the different integer value in same key user defaults.
#IBAction func Button1(_ sender: Any) {
UserDefaults.standard.set(1, forKey:"dissapear")
self.performSegue(withIdentifier: "show", sender: nil)
}
#IBAction func Button2(_ sender: Any) {
UserDefaults.standard.set(2, forKey:"dissapear")
self.performSegue(withIdentifier: "show", sender: nil)
}
#IBAction func Button3(_ sender: Any) {
UserDefaults.standard.set(3, forKey:"dissapear")
self.performSegue(withIdentifier: "show", sender: nil)
}
Here is how I would write this code, if I were sticking to the same UserDefaults storage. Note: you need to reconnect cardPressed(_:) to every button/card
import UIKit
class ViewController: UIViewController {
#IBOutlet var buttonA: UIButton!
#IBOutlet var buttonB: UIButton!
#IBOutlet var buttonC: UIButton!
let buttonKeyPairs: [(button: UIButton, key: String)] = [
(buttonA, "dissapear"),
(buttonB, "dissapear2"),
(buttonC, "dissapear3"),
]
override func viewDidLoad() {
super.viewDidLoad()
for (button, key) in buttonKeyPairs
where UserDefaults.standard.integer(forKey: key) == 1 {
button.setImage(UIImage(named: "wildcardbackingblack.png"), for: .normal)
button.isEnabled = false
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPressed(_ sender: UIButton) {
let key: String
switch UIButton {
case buttonA: key = "dissapear"
case buttonB: key = "dissapear2"
case buttonC: key = "dissapear3"
}
UserDefaults.standard.set(1, forKey: key)
self.performSegue(withIdentifier: "show", sender: self)
}
}
How do i set up a label so that when a button is pressed then it will change that value displayed on the label and set it up that each time a button is pressed it they will all just add to the previous number that was pressed - and is it possible to set up 2 view scenes on the same view controller?
#IBOutlet weak var creditLabel: UILabel!
var savedNum:Int = "Credits: /0"
var Money : Int!
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.
}
#IBAction func oneDollar(_ sender: Any) {
let oneDollar = 1
}
#IBAction func fiveDollars(_ sender: Any) {
let fiveDollars = 5
}
#IBAction func tenDollars(_ sender: Any) {
let tenDollars = 10
}
#IBAction func twentyDollars(_ sender: Any) {
let twentyDollars = 20
}
#IBAction func fiftyDollars(_ sender: Any) {
let fiftyDollars = 50
}
#IBAction func oneHundredDollars(_ sender: Any) {
let oneHundredDollars = 110
}
}
I think what you're trying to do is something like this…
class ViewController: UIViewController {
#IBOutlet weak var creditLabel: UILabel!
var credit = 0 {
didSet {
creditLabel.text = "Credit: $\(credit)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
credit = 0
}
#IBAction func oneDollar(_ sender: Any) {
credit += 1
}
#IBAction func fiveDollars(_ sender: Any) {
credit += 5
}
// etc
}
Is your Label connected to your UIViewController? What about the corresponding actions? Are you connecting the same actions to the same button? Need more information to help solve your error that's being thrown.
Please, before you mark this question as duplicate, I want to know why my code is failing, not to be send to another one that is working.
I am a newbie in swift and I would like to send a variable "um_words" (which is calculated when a button is clicked) from a viewController when the same button is clicked, save that variable in the secondViewController and show it in a textView. To do so I have tried with many modifications of this code, which is giving no errors in the console but not showing the value of the variable on the textView:
1st VC
import UIKit
import Foundation
class TransViewController: UIViewController {
#IBOutlet var trad_text: UITextView!
#IBOutlet var buttonTrad: UIButton!
#IBOutlet var labelsitoh: UILabel!
var num_words = 0
#IBAction func butCalc(_ sender: UIButton) {
let text = trad_text.text
num_words = (text?.components(separatedBy: " ").count)!-1
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var DestViewController : PaymentViewController = segue.destination as! PaymentViewController
DestViewController.num_words = String(num_words)
}
}
override func viewDidLoad() {
super.viewDidLoad()
trad_text!.layer.borderWidth = 1
trad_text!.layer.cornerRadius = 20
trad_text!.layer.borderColor = UIColor(red:0.22, green:0.26, blue:0.39, alpha:1.0).cgColor
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
2nd VC
import UIKit
import Foundation
class PaymentViewController: UIViewController {
#IBOutlet var labelImport: UITextView!
var num_words = String()
override func viewDidLoad() {
super.viewDidLoad()
labelImport.text = num_words
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I have ab hypothesis of why it is not working: the function "prepare" is not being called; it only goes to next VC when the button is clicked...
Thank you for your time.
The func prepare should be outside of the button action, it will be called when segue is triggered.
#IBAction func butCalc(_ sender: UIButton) {
let text = trad_text.text
num_words = (text?.components(separatedBy: " ").count)!-1
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var DestViewController : PaymentViewController = segue.destination as! PaymentViewController
DestViewController.num_words = String(num_words)
}
See:
IBAction func butCalc(_ sender: UIButton) {
let text = trad_text.text
num_words = (text?.components(separatedBy: " ").count)!-1
self.performSegue(withIdentifier: "yourSegueIdentifier", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "yourSegueIdentifier") {
var destViewController : PaymentViewController = segue.destination as! PaymentViewController
destViewController.num_words = String(num_words)
}
}
You have create a function in another function...
Please try this.
PS: I did not test this code
I have the following:
class Settings: UIViewController {
#IBAction func CitySend(sender: AnyObject) {
self.performSegue(withIdentifier: "senddata", sender: self)
}
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "senddata" {
let Mainview = segue.destination as! ViewController
Mainview.label = textField.text!
}
}
}
My mainview looks like this:
class ViewController: UIViewController {
#IBOutlet var city: UILabel!
var label: String = ""
override func viewDidLoad() {
super.viewDidLoad()
city.text = label
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
im not sure, if this is how i should even do this, but to me the logic is that i only want to allow this segue to pass a string to my label in my mainview if the button is pressed (Like a save button)
However as to what i have made now, nothing happens, and it gives me the 1: signal SIGABRT error, whenever i press the button.
Use the following code:
ViewController.swift
import UIKit
class ViewController: UIViewController, SecondViewControllerProtocol{
#IBOutlet weak var dataLabel: UILabel!
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.
}
#IBAction func navigateToSecondViewControllerOnButtonClick(_ sender: AnyObject) {
let secondVC: ViewController2 = storyboard?.instantiateViewController(withIdentifier: "viewcont2") as! ViewController2
secondVC.delegate = self
self.navigationController?.pushViewController(secondVC, animated: true)
}
func saveData(data: String){
dataLabel.text = data
}
}
ViewController2.swift
import UIKit
protocol SecondViewControllerProtocol {
func saveData(data: String) // this function the first controllers
}
class ViewController2: UIViewController {
var delegate: SecondViewControllerProtocol?
#IBOutlet weak var dataTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func saveButtonClicked(_ sender: AnyObject) {
delegate?.saveData(data: dataTextField.text!)
}
}
Storyboard screenshot:
Please check my GitHub link below to test sample:
https://github.com/k-sathireddy/PassingDataThroughSegue
#IBAction func CitySend(sender: AnyObject) {
self.performSegue(withIdentifier: "senddata", sender: textField.text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch (segue.identifier, segue.destination, sender) {
case (.Some("senddata"), let controller as ViewController, let text as String):
controller.label = text
default:
break
}
}