Connecting Two UISegmentedControllers - ios

I have been having trouble synchronizing the values of two UISegments. The First UISegment is suppose to get updated based on the value of the second UISegment (which is in a different ViewController) and then update the value in its own segment based on what is selected in the second ViewController. However, the values are not transferring to the first UISegment, meaning the title and value is not being stored even though I am using the defaults and storing keys.
ViewController
import UIKit
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()
billField.text = String(defaults.double(forKey: "bill_value"))
print(tipController.selectedSegmentIndex)
if billField.text == "" || (billField.text == nil) {
billField.placeholder = String(0.00)
}
billField.becomeFirstResponder()
tipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
}
override func viewWillAppear(_ animated: Bool) {
tipController.selectedSegmentIndex = defaults.integer(forKey: "default_tip_index")
}
#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 //converts bill to double
defaults.set(bill, forKey: "bill_value") //Saves last bill input
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])))
}
}
SettingsViewController
class SettingsViewController: UIViewController {
var tipPercentageIndex:Int!
#IBOutlet weak var settingsTipController: UISegmentedControl!
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
let selectedDefaultPercent = defaults.integer(forKey: "default_tip_index")
settingsTipController.selectedSegmentIndex = selectedDefaultPercent
}
#IBAction func tipPercent(_ sender: Any) {
defaults.set(settingsTipController.selectedSegmentIndex, forKey: "default_tip_index")
defaults.synchronize()
}
#IBAction func splitNumber(_ sender: Any) {
}
#IBAction func Back(_ sender: Any) {
self.performSegue(withIdentifier: "Tippy2", sender: self)
}
}
Overall this simple application calculates the tip and updates the first UISegment when the settingsViewController is visited.

Related

UIImageView Array iOS13

I am trying with learning Swift and got stuck on an issue here.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
var leftDiceNumber=1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
diceImageView1.image = UIImage(imageLiteralResourceName: "DiceSix")
// change transparency with diceImageView1.alpha=0.7
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
diceImageView1 = [ UIImageView(imageLiteralResourceName: "DiceOne"),UIImageView(imageLiteralResourceName: "DiceTwo"),UIImageView(imageLiteralResourceName: "DiceThree"),UIImageView(imageLiteralResourceName: "DiceFour"),UIImageView(imageLiteralResourceName: "DiceFive"),UIImageView(imageLiteralResourceName: "DiceSix")],[leftDiceNumber]
leftDiceNumber=leftDiceNumber+1
}
}
But all I get is the error messages on the IBAction:
1.Argument passed to call that takes no arguments
2.Cannot assign value of type '[UIImageView]' to type 'UIImageView'
3.Consecutive statements on a line must be separated by ';'
4.Expected expression
What's the difference between UIImageView and UIImage ? When they should be used?
Many Thanks in advance !
You want to change the .image property to change the image.
To "cycle through" the dice, you could do this:
class DiceViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
let diceNames: [String] = [
"DiceOne", "DiceTwo", "DiceThree", "DiceFour", "DiceFive", "DiceSix"
]
var leftDiceNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
diceImageView1.image = UIImage(named: diceNames[leftDiceNumber % 6])
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
// increment the index
leftDiceNumber += 1
// udpate the image view
diceImageView1.image = UIImage(named: diceNames[leftDiceNumber % 6])
}
}
I'm guessing your goal is to "randomly roll" the dice, so take a look at this slightly different class:
class DiceViewController: UIViewController {
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
let diceNames: [String] = [
"DiceOne", "DiceTwo", "DiceThree", "DiceFour", "DiceFive", "DiceSix"
]
override func viewDidLoad() {
super.viewDidLoad()
// start with both dice at One
diceImageView1.image = UIImage(named: diceNames[0])
diceImageView2.image = UIImage(named: diceNames[0])
}
#IBAction func rollButtonPressed(_ sender: UIButton) {
print("button pressed")
// arrays are Zero-based, so get a random Int
// from 0 to 5
//let l = Int.random(in: 0...5)
//let r = Int.random(in: 0...5)
//diceImageView1.image = UIImage(named: diceNames[l])
//diceImageView2.image = UIImage(named: diceNames[r])
// more "modern Swifty" method
if let nm = diceNames.randomElement() {
diceImageView1.image = UIImage(named: nm)
}
if let nm = diceNames.randomElement() {
diceImageView2.image = UIImage(named: nm)
}
}
}

Why segues does not work? can not switch view

**Not quite sure why the view is not changing when the button Calculate
is pressed?
What are the possible reasons for that? Could you please help?
import UIKit
class CalculateViewController: UIViewController {
#IBOutlet weak var heightLabel: UILabel!
#IBOutlet weak var weightLabel: UILabel!
#IBOutlet weak var heightSlider: UISlider!
#IBOutlet weak var weightSlider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func heightSlided(_ sender: UISlider) {
var currentHeightValue = sender.value
let roundedHeightValue = String(format: "%.2f", currentHeightValue)
heightLabel.text = "\(roundedHeightValue)m"
}
#IBAction func weightSlided(_ sender: UISlider) {
var currentWeightValue = sender.value
let roundedWeightValue = String(format: "%.0f", currentWeightValue)
weightLabel.text = "\(roundedWeightValue)kg"
}
#IBAction func calculateBMI(_ sender: UIButton) {
var squareOfHeight = Float(pow(heightSlider.value, 2.0))
var BMI = weightSlider.value / squareOfHeight
self.performSegue(withIdentifier: "goToResult", sender: self)
}
}
try this..
let storyBoard: UIStoryboard = UIStoryboard(name: "Name
Storyboard", bundle: nil)
if let push = storyBoard.instantiateViewController(withIdentifier: "Name Storyboar
ID") as? Name View Controller {
self.navigationController?.pushViewController(push, animated: true)
}

Swift NSTiimer not following specified Interval

I am trying to create a quiz app which has a timer for each question when the timer expires (i.e. 10 seconds and I want Timer to have an interval of 1 sec) it resets it self and next question is fetched and Timer again restart from 10... But my issue is the timer doesn't follow a fixed interval when first question is loaded it shows interval of 2 ... i.e. 10,8,6 .. and then for second question it makes jump for 3 secs interval and similarly the interval increases.
import UIKit
class ViewController: UIViewController {
let allQuestions = QuestionsBundle()
var pickedAnswer : Int = 0
var questionCounter = 0
var score : Int = 0
var timer: Timer!
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var countDownLabel: UILabel!
#IBOutlet weak var ansLbl1: UILabel!
#IBOutlet weak var ansLbl2: UILabel!
#IBOutlet weak var ansLbl3: UILabel!
#IBOutlet weak var ansLbl4: UILabel!
#IBOutlet weak var checkBox1: CheckBox!
#IBOutlet weak var checkBox2: CheckBox!
#IBOutlet weak var checkBox3: CheckBox!
#IBOutlet weak var checkBox4: CheckBox!
var checkBoxlist : [CheckBox] = []
#IBAction func correct_Answer_Checbox_Btn(_ sender: AnyObject) {
//print("\(sender.tag) <==> \(String(describing: question?.correctAnswer))")
updateCheckBoxes(sender: sender)
if sender.tag == question?.correctAnswer{
question?.isAnswerCorrect = true
question?.selectedAnswer = sender.tag
//score = score + 1
}
else {
question?.isAnswerCorrect = false
}
}
func updateCheckBoxes(sender: AnyObject){
for checkBoxItem in checkBoxlist{
if checkBoxItem.tag != sender.tag {
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var nextButton: UIButton!
#IBAction func nextBtnClicked(_ sender: AnyObject) {
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
func handleNextQuestion() throws {
nextQuestion()
if questionCounter == allQuestions.list.count-1{
finishButton.isHidden = false
nextButton.isHidden = true
//scoreLbl.text = "\(score)"
}
}
var question : Question?
var countTime = 10.0
override func viewDidLoad() {
super.viewDidLoad()
finishButton?.isHidden = true
checkBoxlist = fetchCheckBoxList()
question = fetchQuestion()
setQuizView(question: question!)
// Do any additional setup after loading the view, typically from a nib.
}
// set all questions in a function
#objc func update() {
if(countTime > 0) {
countTime = countTime - 1
self.countDownLabel.text = String(countTime)
}else{
timer.invalidate()
countTime = 10.0
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: true)
}
func setQuizView(question:Question) {
self.countDownLabel.text = "10"
startTimer()
questionLabel.text = question.questionText
ansLbl1.text = question.answer1
ansLbl2.text = question.answer2
ansLbl3.text = question.answer3
ansLbl4.text = question.answer4
if question.selectedAnswer == Constants.DEFAULT_ANSWER {
for checkBoxItem in checkBoxlist{
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var finishButton: UIButton!
// prepare segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == resultScreenIdentifier{
let vc = segue.destination as! ResultViewController
vc.data = sender as! String
}
}
let resultScreenIdentifier = "resultScreenSegue"
func moveToResultView(){
performSegue(withIdentifier: resultScreenIdentifier, sender: score)
}
#IBAction func finishButtonClicked(_ sender: UIButton) {
//perform segue
let score = "\(calculateScore())"
moveToResultView()
}
// calculate the score of quiz using loop
func calculateScore()->Int{
var numOfCorrectAnswers = 0
for question in allQuestions.list{
if question.isAnswerCorrect {
numOfCorrectAnswers = numOfCorrectAnswers + 1
//print(numOfCorrectAnswers)
}
}
return numOfCorrectAnswers
}
func nextQuestion(){
showResultView(isCorrect: (question?.isAnswerCorrect)!)
questionCounter = questionCounter + 1
question = fetchQuestion()
setQuizView(question: question!)
}
func fetchQuestion() -> Question{
return allQuestions.list[questionCounter]
}
func fetchCheckBoxList() -> [CheckBox]{
let arr : [CheckBox] = [checkBox1,checkBox2,checkBox3,checkBox4]
return arr
}
}
Timers are not particularly accurate. They can suffer from significant jitter.
A better approach is to create a Date that represents the expiration time (ie Date(timeIntervalSinceNow:10) and then run a Timer with a much shorter interval (I would suggest around 0.1 second). You can then calculate the time remaining based on the target Date and check if the target date is in the past.

Keep getting "Cannot assign to value: 'calculateBMI' is a method" when using a struct

I keep getting "Cannot assign to value: 'calculateBMI' is a method" error message when using a struct property. any way around this. This is my code from the struct:
import UIKit
struct Calculations {
var bmi : Float = 0.0
func getBMIValue() -> String {
let BMIRounded = String(format: "%.1f", bmi)
return BMIRounded
}
mutating func calculateBMI (height: Float, weight: Float) {
bmi = weight / (height * height)
}
}
and this is where I get the error message on my First Page View controller:
import UIKit
class HomeViewController: UIViewController {
var calculations = Calculations()
#IBOutlet weak var heightLabel: UILabel!
#IBOutlet weak var weightLabel: UILabel!
#IBOutlet weak var heightSlider: UISlider!
#IBOutlet weak var weightSlider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func HeightSliderChange(_ sender: UISlider) {
var height = String (format: "%.2f", sender.value)
heightLabel.text = "\(height)m"
print(height)
}
#IBAction func WeightSliderChange(_ sender: UISlider) {
var weight = String (format: "%.0f", sender.value)
weightLabel.text = "\(weight)kg"
}
#IBAction func calculatePressed(_ sender: Any) {
let height = heightSlider.value
let weight = weightSlider.value
calculations.calculateBMI = (height: height, weight: weight)
self.performSegue(withIdentifier: "GettingResults", sender: self)
}
}
The error happens on line 43 (calculations.calculateBMI)
As the error states clearly you are trying to set calculateBMI which is a function and not a variable. To fix this issue modify your calculatePressed method like this:
#IBAction func calculatePressed(_ sender: Any) {
let height = heightSlider.value
let weight = weightSlider.value
calculations.calculateBMI(height: height, weight: weight)
self.performSegue(withIdentifier: "GettingResults", sender: self)
}

Prepare for segue, passing data

Hey guys I need some help here with my code, please take a look to the images to see what I see. I'm making a Tip Calculator Project in Swift and I must have a settings view where I select the default tip rate. I have some errors and I must fix that as soon as posible. I will really appreciate that some one corrects my code and test it. Below is the code of the two ViewControllers, I did not post the image of the Settings View Controller because the website does not let me post more than two links until I get more reputation.
The error in Xcode:
Storyboard: Check the images I have some errors at the first lines.
import UIKit
class ViewController: UIViewController, SettingDelegate {
// Inputs
#IBOutlet weak var amountTextField: UITextField!
//Labels
#IBOutlet weak var TipPercentageLabel: UILabel!
#IBOutlet weak var numberOfPersonLabel: UILabel!
#IBOutlet weak var tipAmountLabel: UILabel!
#IBOutlet weak var totalBillLabel: UILabel!
#IBOutlet weak var billPerPersonLabel: UILabel!
//Slider & Stepper
#IBOutlet weak var tipSlider: UISlider!
#IBOutlet weak var personsStepper: UIStepper!
//Variables
var tipPercentage : Double = NSUserDefaults.standardUserDefaults().doubleForKey("DefaultTipRate") ?? 0.20
var numberOfPerson:Int = 1
let numberFormatter:NSNumberFormatter = NSNumberFormatter()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tipAmountLabel.text = "$0.00"
totalBillLabel.text = "Bill Total"
billPerPersonLabel.text = "$0.00"
TipPercentageLabel.text = "20.0%"
numberOfPersonLabel.text = "1"
self.amountTextField.becomeFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupContainer() {
tipSlider.minimumValue = 0
tipSlider.maximumValue = 100
tipSlider.value = 20
tipSlider.addTarget(self, action: "sliderTipChanged:", forControlEvents: .ValueChanged)
personsStepper.minimumValue = 1
personsStepper.maximumValue = 30
personsStepper.value = 1
personsStepper.addTarget(self, action: "sliderPersonChanged:", forControlEvents: .ValueChanged)
amountTextField.text = ""
refreshCalculation()
}
#IBAction func OnEditingFieldBill(sender: AnyObject) {
refreshCalculation()
}
func refreshCalculation() {
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
if let amount = numberFormatter.numberFromString(amountTextField.text!) as? Double {
let tipAmount = amount * tipPercentage
let totalBill = amount + tipAmount
let billPerPerson = totalBill / Double(numberOfPerson)
numberFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
tipAmountLabel.text = numberFormatter.stringFromNumber(tipAmount)
totalBillLabel.text = numberFormatter.stringFromNumber(totalBill)
billPerPersonLabel.text = numberFormatter.stringFromNumber(billPerPerson)
} else {
tipAmountLabel.text = "-"
totalBillLabel.text = "-"
billPerPersonLabel.text = "-"
}
numberFormatter.numberStyle = NSNumberFormatterStyle.PercentStyle
numberFormatter.minimumFractionDigits = 1
numberFormatter.maximumFractionDigits = 1
TipPercentageLabel.text = self.numberFormatter.stringFromNumber(tipPercentage)
numberOfPersonLabel.text = "\(numberOfPerson)"
}
#IBAction func sliderTipChanged(sender: UISlider) {
tipPercentage = Double(round(tipSlider.value)) / 100
refreshCalculation()
}
#IBAction func StepperPersonChanged(sender: UIStepper) {
numberOfPerson = Int(round(personsStepper.value))
refreshCalculation()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let SettingsViewController = segue.destinationViewController as?SettingsViewController {
SettingsViewController.delegate = self
refreshCalculation()
}
}
}
The SettingsViewController below:
import UIKit
protocol SettingDelegate {
func tipPercentageChanged(newValue : Double)
}
class SettingsViewController: UIViewController {
var destName : String!
var delegate : SettingDelegate?
#IBOutlet weak var tipControl: UISegmentedControl!
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 DefaultRate(sender: AnyObject) {
var tipRates = [0.05, 0.10, 0.15, 0.20, 0.25, 0.30]
let tipRate = tipRates[tipControl.selectedSegmentIndex]
delegate?.tipPercentageChanged(tipRate)
NSUserDefaults.standardUserDefaults().setDouble(tipRate, forKey: "DefaultTipRate")
NSUserDefaults.standardUserDefaults().synchronize()
}
/
For your first error:
When a viewController conforms to a protocol, it needs to implements the methods the protocol implements. In your case, define you should have
func tipPercentageChanged(newValue : Double) {
//save the new value here
}
The first error should go away.
It looks like you are presenting the SettingsViewController using a modal transition, so you can use
self.dismissViewControllerAnimated(true, completion: {})

Resources