how to use uistepper to multiply value from segue data transfer [closed] - swift

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
So I came across this question that relates to mine and I was wondering how I can do this with a value from a segue data transfer. I want to be able to use my data transfer value as the original value and only have that value change if the stepper value changes.
For example my original value is 5 when the stepper value increases, 10, 15, 20, 25 ... and so on, and same thing for when it decreases. How can I go about doing this?
Here is my data transfer function :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == Constants.Segues.fromEventDetailsToTicketForm {
guard let user = Auth.auth().currentUser else { return }
let vc = segue.destination as! TicketFormViewController
vc.ticketHolderName = user.displayName
vc.costOfEvent = selectedEventCost
vc.dateOfEvent = selectedEventDate
vc.navigationItem.title = selectedEventName
}
}
Here is the global variables in my destination vc:
#IBOutlet weak var nameOfTicketHolderLabel: UILabel!
#IBOutlet weak var nameOTicketHolderTextF: UITextField!
#IBOutlet weak var numberOfGuestsLabel: UILabel!
#IBOutlet weak var dateOfEventLabel: UILabel!
#IBOutlet weak var actualDateOfEvent: UILabel!
#IBOutlet weak var totalCostOfEventLabel: UILabel!
#IBOutlet weak var actualCostOfEvent: UILabel!
#IBOutlet weak var guestNumberCount: UILabel!
var ticketHolderName: String?
var costOfEvent: String?
var dateOfEvent: String?
var nameOfEvent: String?
And this is the function I use to connect everything:
func dataTransferVerification() {
if let nameToLoad = ticketHolderName {
nameOTicketHolderTextF.text = nameToLoad
}
if let costToLoad = costOfEvent {
actualCostOfEvent.text = costToLoad
}
if let dateToLoad = dateOfEvent {
actualDateOfEvent.text = dateToLoad
}
if let nameToLoad = nameOfEvent {
navigationItem.title = nameToLoad
}
}
The UIStepper func, I have no idea what to put in here:
#IBAction func guestsCount(_ sender: UIStepper) {
guestNumberCount.text = String(Int(sender.value))
}
Now I want to know, with what I got, how to use the cost value and make it original so when the stepper value changes, the original value never changes. Say it's $5.00 when the data transfers over, I only want $5 to be multiplied by the stepper value, I don't want it to change value.

First, you'll want to get a numerical version of your cost string.
At the top of your view controller:
private var costDecimal : Decimal = 0
In your "data transfer" as you call it (you could do this before or after the segue -- doesn't really matter):
let formatter = NumberFormatter()
formatter.numberStyle = .currency
if let number = formatter.number(from: str) {
let amount = number.decimalValue
print(amount)
self.costDecimal = amount
}
(taken from https://stackoverflow.com/a/41884823/560942)
Now, in your stepper:
#IBAction func guestsCount(_ sender: UIStepper) {
guestNumberCount.text = String(Int(sender.value))
//multiply sender.value by the cost that was passed in
let totalCost = Decimal(sender.value) * costDecimal
}

Related

displaying user email on viewcontroller gives optional"email adress" [duplicate]

This question already has answers here:
How to remove optional text from json Result In swift
(3 answers)
Optional Text in Alert in ResetPassword - iOS Project using Swift
(2 answers)
Closed 1 year ago.
So I'm using firebase Authentication in my ios app, and I want to display the email address, and Username in UIlabels on a viewcontroller. But when i display the value of Auth.auth().email on a UIlabel, the Label would show Optional"email adress".How do i get rid of the Optional and also how to allow the user to have a display name in firebase Authentication?
import Firebase
import FirebaseAuth
class ProfileViewController: UIViewController {
#IBOutlet weak var profiepic: UIImageView!
#IBOutlet weak var UsernameLabel: UILabel!
#IBOutlet weak var EmailLabel: UILabel!
#IBOutlet weak var league: UILabel!
#IBOutlet weak var Achievements: UIButton!
#IBOutlet weak var resetpasswd: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
UsernameLabel.layer.borderColor = UIColor.black.cgColor
EmailLabel.layer.borderColor = UIColor.black.cgColor
league.layer.borderColor = UIColor.black.cgColor
Achievements.layer.cornerRadius = 55/2
resetpasswd.layer.cornerRadius = 55/2
resetpasswd.layer.borderColor = UIColor.black.cgColor
displayinfo()
}
func displayinfo() {
let user = Auth.auth().currentUser
if let user = user {
// The user's ID, unique to the Firebase project.
// Do NOT use this value to authenticate with your backend server,
// if you have one. Use getTokenWithCompletion:completion: instead.
let email = user.email
let photoURL = user.photoURL
EmailLabel.text = "Email: \(email)"
// ...
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
You need to use if or guard to display string info properly.
Using if:
func displayinfo() {
let user = Auth.auth().currentUser
if let user = user {
if let email = user.email {
EmailLabel.text = "Email: \(email)"
}
if let photoURL = user.photoURL {
...
}
// ...
}
}
Using guard:
func displayinfo() {
guard let user = Auth.auth().currentUser else {
print("No user info found")
return
}
if let email = user.email {
EmailLabel.text = "Email: \(email)"
//EmailLabel.text = "Email: " + email
}
if let photoURL = user.photoURL {
...
}
// ...
}
Let me know if you have any issue in these solutions.
Apart from this, I would rather write UIViewController in this manner which seems to be a more clearer approach.
class ProfileViewController: UIViewController {
#IBOutlet weak var profiepic: UIImageView!
#IBOutlet weak var lblUsername: UILabel! {
didSet {
lblUsername.layer.borderColor = UIColor.black.cgColor
}
}
#IBOutlet weak var lblEmail: UILabel! {
didSet {
lblEmail.layer.borderColor = UIColor.black.cgColor
}
}
#IBOutlet weak var lblLeague: UILabel! {
didSet {
lblLeague.layer.borderColor = UIColor.black.cgColor
}
}
#IBOutlet weak var btnAchievements: UIButton! {
didSet {
btnAchievements.layer.cornerRadius = 55/2
// For button height, instead of 55 here you can use, btnAchievements.bounds.height / 2 or use constrain also to change button height when bound changes
}
}
#IBOutlet weak var btnReset: UIButton! {
didSet {
btnReset.layer.cornerRadius = 55/2
btnReset.layer.borderColor = UIColor.black.cgColor
}
}
private var currentUser: AuthUser? {// Type of Auth.auth().currentUser
didSet {
// Use above code for displayInfo or simply call displayInfo from here
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.currentUser = Auth.auth().currentUser
}
...
}
I hope this would help you designing other UIViewControllers as well.

Swift/Xcode: trying to access local variable that gets updated in another function

I'm a beginner and I am struggling with a certain problem regarding local variables. Specifically, I am trying to make an app where I test certain fraction questions. So, I need to generate random numbers for the test and access them so that the checker function can make sure the user got the right answer. However, if I generate a new set of numbers when the user clicks "ask question", the other checker function doesn't know what those numbers are... Here is my code below:
class ViewControllerEasy: UIViewController {
#IBOutlet weak var giveQuestionOutlet: UIButton!
#IBOutlet weak var nextButtonOutlet: UIButton!
#IBAction func nextQuestionButton(_ sender: Any) {
nextButtonOutlet.isHidden = true
giveQuestionOutlet.isEnabled = true
easyQuestionResponse.text = ""
easyQuestionLabel.text = ""
resultLabel.text = ""
}
#IBOutlet weak var easyQuestionResponse: UITextField!
#IBOutlet weak var easyQuestionLabel: UILabel!
#IBAction func easyQuestionButton(_ sender: Any) {
let num1 = Int.random(in: 1 ..< 6)
let num2 = Int.random(in: 2 ..< 11)
easyQuestionLabel.text = "What percentage does \(num1) / \(num2) represent? (Round down to the closest whole number)"
}
#IBOutlet weak var resultLabel: UILabel!
#IBAction func checkButton(_ sender: Any) {
let expectedAnswer = ((num1 * 100) / num2)
let expectedAnswer2 = Float(expectedAnswer)
if Float(easyQuestionResponse.text!) == round(expectedAnswer2) {
resultLabel.text = "Great Job! Correct Answer."
nextButtonOutlet.isHidden = false
giveQuestionOutlet.isEnabled = false
}else {
resultLabel.text = "Sorry, that is incorrect. The correct answer was: \(round(expectedAnswer2))%"
nextButtonOutlet.isHidden = false
giveQuestionOutlet.isEnabled = false
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let invalidCharacters = CharacterSet(charactersIn: "0123456789").inverted
return string.rangeOfCharacter(from: invalidCharacters) == nil
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
So, how can I generate new questions when the user clicks the button to ask for it and also make sure that the code can check whether or not the user got the right answer? I tried looking at using a global variable, but that would keep the values same after the first execution of the random numbers call. Thus, I hope someone can help me with this problem. Thanks in advance.

How do I store a calculated result in UserDefaults to display in a "results" View controller [duplicate]

This question already has answers here:
How can I use UserDefaults in Swift?
(14 answers)
Closed 4 years ago.
First time poster so sorry for the incorrect format/length of the question.
I am building an app in Xcode that allows users to input various inputs among numerous view controllers and then have output in a single view controller with results displayed through labels.
The raw inputted textfield data is stored into UserDefaults and can display them later in the resulting VC with no problem. Im having trouble with calculated outputs (in this example "papiresult") however.
Can anyone provide guidance how to print out the calculated result several view controllers later using UserDefaults?
This is the rough layout
Here is the code I have in the first ViewController:
import UIKit
let userDefaults = UserDefaults()
var papiresult = Double()
class ViewController1: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
#IBOutlet weak var textField3: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField1.delegate = self
textField2.delegate = self
textField3.delegate = self
}
//Declaring data input into UserDefaults//
#IBAction func sendDataToVC2(_ sender: Any) {
let systPA = Double(textField1.text!)
let diastPA = Double(textField2.text!)
let cvPressure = Double(textField3.text!)
papiresult = ((systPA!-diastPA!)/cvPressure!)
userDefaults.set(textField1.text, forKey: "PASP")
userDefaults.set(textField2.text, forKey: "PADP")
userDefaults.set(textField3.text, forKey: "CVP")
userDefaults.set(papiresult, forKey: "PAPI")
}
}
Here is the code in the last (result) view controller:
import UIKit
class ViewController3: UIViewController {
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
#IBOutlet weak var label4: UILabel!
#IBOutlet weak var label5: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
//Recalling data from UserDefaults//
override func viewWillAppear(_ animated: Bool) {
if let data1 = userDefaults.object(forKey: "PASP") {
if let message1 = data1 as? String {
self.label1.text = message1}
}
if let data2 = userDefaults.object(forKey: "PADP") {
if let message2 = data2 as? String {
self.label2.text = message2}
}
if let data3 = userDefaults.object(forKey: "CVP") {
if let message3 = data3 as? String {
self.label3.text = message3}
}
if let data4 = userDefaults.object(forKey: "Age") {
if let message4 = data4 as? String {
self.label4.text = message4}
}
if let data5 = userDefaults.object(forKey: "PAPI") {
if let message5 = data5 as? Double {
self.label5.text = "\(message5)"}
}
}
Basically, you should use UserDefaults.standard rather than creating a new instance of UserDefaults class. So I think this code
let userDefaults = UserDefaults()
should be replaced with this:
let userDefaults = UserDefaults.standard

NSPopUpButton selection to Float Swift 4

I am trying to get a String value to a Float value from a NSPopUpButton.
E.g. I have 3 number selections. 50, 20, 10. When the user selects one of the numbers I would like a calculation made into a Float value.
I know this may be something very simple but I am new and I can't find anything on Stackoverflow. Any help would be appreciated. Here is an example of the code I have.
#IBOutlet weak var userInput: NSTextField!
#IBOutlet weak var result: NSTextField!
#IBOutlet weak var userMenuSelection: NSPopUpButton!
override func viewDidLoad() {
super.viewDidLoad()
userMenuSelection.removeAllItems()
userMenuSelection.addItems(withTitles: ["50", "20", "10"])
}
#IBAction func pushButtonforResult(_ sender: Any) {
/*
Not sure how to take the selected userMenuSelection and multiply it by the users input to get my result in a float.
E.g. look below. This of course does not work because the menu items are strings.
*/
result.floatValue = userMenuSelection * userInput.floatValue
}
Hope this makes sense to what I am asking.
As you see, your userMenuSelection has titles representing the Float values as String.
You can simply retrieve the selected title and convert it to Float:
#IBAction func pushButtonforResult(_ sender: Any) {
var selectedValue = Float(userMenuSelection.titleOfSelectedItem ?? "0") ?? 0.0
result.floatValue = selectedValue * userInput.floatValue
}
You can try
let arr = ["50", "20", "10"]
//
#IBAction func pushButtonforResult(_ sender: NSPopUpButton) {
let selectedValue = Float(arr[sender.selectedTag()])!
Result.floatValue = selectedValue * userInput.floatValue
// OR
let selectedValue = Float(sender.selectedItem!.title)!
result.floatValue = selectedValue * userInput.floatValue
}

Displaying an Array of type Double on UILabel in Xcode

I am trying to make a basic shopping cart app where you can add an item to your cart, store the cost of the item in an array and then have the array displayed when you click "Receipt". However, every time I click "Receipt" on my app, the simulator crashes and displays
"Thread1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)
beside my line of code that reads "allItems += item". If anyone has any ideas as to how I can my array of numbers displayed in a UILabel using a for in loop, please let me know. I will post source code below. Thanks in advance
class ViewController: UIViewController {
var priceOfApple = 1.75
var cart = [Double]()
var total = 0.00
#IBOutlet weak var appName: UILabel!
#IBOutlet weak var Balance: UILabel!
#IBOutlet weak var Instructions: UILabel!
#IBOutlet weak var redApple: UIButton!
#IBOutlet weak var appleInfo: UILabel!
#IBOutlet weak var addToCart: UIButton!
#IBOutlet weak var itemsPurchased: UILabel!
#IBAction func selectedApple(sender: AnyObject) {
Instructions.hidden = true
appleInfo.hidden = false
addToCart.hidden = false
}
#IBAction func purchaseApple(sender: AnyObject) {
cart.append(priceOfApple)
total += priceOfApple
Balance.text = "Balance : \(total)"
Instructions.hidden = false
appleInfo.hidden = true
addToCart.hidden = true
}
#IBAction func viewReceipt(sender: AnyObject) {
redApple.hidden = true
Instructions.hidden = true
itemsPurchased.hidden = false
for item in cart {
var allItems = Double(itemsPurchased.text!)!
allItems += item
allItems = Double(itemsPurchased.text!)!
}
}
}
If I understand correctly, this is what you should do:
First, create a variable outside the for-loop,
then inside the loop that variable will start storing every value in the array separated by " ". Once It is done, you can display its value in the Label.
var itemsInCart = ""
for items in cart{
itemsInCart += String(items) + " "
}
itemsPurchased.text = itemsInCart
I hope it helps!!!
A cleaner and safer way to do it:
let result = cart.flatMap { Double(itemsPurchased.text ?? String()) }.reduce(0: combine: +)
Doing that, you shouldn't get EXC_BAD_INSTRUCTION anymore, but you should still check if is the text convertible to a Double.