0

In this app I'm working on I have 9 UiSwitches that I am using to add fees for pizza topping the choices are

mushroom - 0.10
cheese - 0.20
pepperoni 0.50
sausage - 0.45
jalapeno - 0.40
pineapple - .30
olive - 0.60
ham - .75
bacon 1.00

the are hundreds of possible combinations my question is that how would I be able to have calculate the fees without having to have a whole bunch of if statements because currently that is what I am doing

Konrad Krakowiak
  • 12,285
  • 11
  • 58
  • 45
sky1995
  • 43
  • 1
  • 1
  • 6
  • 2
    Post your existing code please. – i_am_jorf Jan 29 '15 at 20:43
  • 1
    In general, add each `UISwitch` to a collection such as an `NSArray`. Then, you want a loop that iterates over the collection. Outside the loop initialize a total counter to zero. For each item in the collection, if `switch.on` is true, add the cost to the total. – i_am_jorf Jan 29 '15 at 20:44
  • In a real production app, you'd want to download the list of toppings and their prices from your server, so that you wouldn't have to distribute a new app every time you change a price or add or remove a topping from the menu. Do you want a solution for a real production app, or a solution for a toy homework problem? – rob mayoff Jan 29 '15 at 22:33

3 Answers3

1

Just associate a value for each UISwitch in your model and loop through all switches to find out which ones are on. If a switch is on, then add its associated value to the total.

Alternatively, you could implement a delegate for each switch (should be the same object though) that triggers the computation when a switch is tapped.

Alternative #2 (but this is reaaaaaaly ugly): Assign a 'tag' to each UISwitch with the corresponding topping value (tags are integers, though) and sum the tags that are assigned with on switches. Again, really bad coding.

Nicolas B.
  • 1,318
  • 1
  • 11
  • 20
  • The tags being integers isn't really a problem, because one shouldn't use floating-point numbers for money anyways. – jscs Jan 29 '15 at 21:18
  • I like the delegate idea. Then you can update UI in realtime as things change. Be sure to [format currency output correctly and for the current locale](http://stackoverflow.com/questions/11787759/how-to-properly-format-currency-on-ios). I wouldn't use the tag, since things may not be unique. Instead you could just subclass `UISwitch` and add a property for amount. – i_am_jorf Jan 29 '15 at 21:22
  • @Josh: You're right, I was just referring to the Int -> Float conversion for the original poster. – Nicolas B. Jan 29 '15 at 21:24
  • @jeffamaphone Agreed, better: use proper MVC :) – Nicolas B. Jan 29 '15 at 21:26
  • Or, my favorite, a category that does crazy stuff with `objc_setAssociatedObject()`. I digress. – i_am_jorf Jan 29 '15 at 21:28
  • @jeffamaphone I'm pretty sure that you can assign "conflicting" tag values to views. In this case (unless the OP later wants to find a `UISwitch` by its tag), it shouldn't cause an issue. Look at my answer; in my testing, there were no problems. – mbm29414 Jan 29 '15 at 21:34
1

Simply create an NSMutableArray and whenever a UISwitch is toggled add/remove the corresponding value to the NSMutableArray. When the "submit" button or whatever is clicked just iterate the Array and sum all the nodes with a simple for statement

r4id4
  • 5,877
  • 8
  • 46
  • 76
-2

So, here's a way to implement what you want. You associate the price for the topping with the tag property of a UISwitch. Then, you can simply iterate an array of the UISwitch objects you've got, quickly summing up the cost of the selected toppings, no if statements needed:

//  ViewController.swift
import UIKit
class ViewController: UIViewController {

    override func viewDidLoad () {
        super.viewDidLoad()
        setupUserInterface()
    }

    var switches: [UISwitch] = [UISwitch]()
    var toppingNames = ["Mushrooms", "Cheese", "Pepperoni", "Sausage", "Jalapeño", "Pineapple", "Olive", "Ham", "Bacon"]
    var toppingCosts = [10, 20, 50, 45, 40, 30, 60, 75, 100]

    var costLabel: UILabel = UILabel()

    func switchFlipped () {
        var cost: CGFloat = costForSelectedToppings()
        var formatter: NSNumberFormatter = NSNumberFormatter()
        formatter.numberStyle = .CurrencyStyle
        var costString: String = formatter.stringFromNumber((cost))!
        self.costLabel.text = "Cost for toppings: " + costString
    }
    func costForSelectedToppings () -> CGFloat {
        var cost: CGFloat = 0.0
        for swtch: UISwitch in self.switches {
            if (swtch.on == true) {
                cost = cost + (CGFloat)(swtch.tag)
            }
        }
        return cost / 100.0
    }


    func setupUserInterface () {
        var previousLabel: UILabel?
        for i in 0...8 {
            var label: UILabel  = UILabel()
            var swtch: UISwitch = UISwitch()
            self.switches.append(swtch)
            label.text  = self.toppingNames[i]
            swtch.tag   = self.toppingCosts[i]
            label.setTranslatesAutoresizingMaskIntoConstraints(false)
            swtch.setTranslatesAutoresizingMaskIntoConstraints(false)
            swtch.addTarget(self, action: "switchFlipped", forControlEvents: .ValueChanged)
            self.view.addSubview(label)
            self.view.addSubview(swtch)

           self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
                "H:|-[label]-[switch]-|",
                options:NSLayoutFormatOptions(0),
                metrics:nil,
                views:["label"  : label, "switch" : swtch]))
            self.view.addConstraint(NSLayoutConstraint(
                item: swtch,
                attribute:.CenterY,
                relatedBy:.Equal,
                toItem:label,
                attribute:.CenterY,
                multiplier:1.0,
                constant:0.0))

            if let prev = previousLabel {
                self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[label1]-(spacing)-[label2]",
                    options:NSLayoutFormatOptions(0),
                    metrics:["spacing"   : 16],
                    views:["label1" : previousLabel!, "label2": label]))

            } else {
                self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(margin)-[label]",
                    options:NSLayoutFormatOptions(0),
                    metrics:["margin"   : 40],
                    views:["label" : label]))
            }
            previousLabel = label
        }
        self.costLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.costLabel.text = "Cost for toppings: $0.00"

        self.view.addSubview(self.costLabel)
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[label]-|",
            options:NSLayoutFormatOptions(0),
            metrics:nil,
            views:["label"  : self.costLabel]))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[label1]-(spacing)-[label2]",
            options:NSLayoutFormatOptions(0),
            metrics:["spacing"   : 16],
            views:["label1" : previousLabel!, "label2": self.costLabel]))

    }

}

Note: Obviously, you'll probably want to update this UI layout. I'm guessing you'll eventually want to place it either in a UITableView or at least into a UIScrollView in case the contents run off-screen.

mbm29414
  • 11,558
  • 6
  • 56
  • 87
  • 1
    UITableViews with proper MVC design pattern is real solution here, this is really repetitive code. – Nicolas B. Jan 29 '15 at 21:35
  • @NicolasB. Guess you didn't read the whole answer. ;-) Also, it's not repetitive. It may be verbose, but each control is created for a different (albeit similar) purpose. Anyway, this is illustrative of **an** answer to the OP's question, not **the** answer. Any final answer is going to be constrained by actual business needs. – mbm29414 Jan 29 '15 at 21:36
  • 1
    No, no, I did read your whole answer, just confirming your words. As this is crying for a real+clean refactoring :) – Nicolas B. Jan 29 '15 at 21:38