0

I’m a newbie self teaching myself iOS development (100DaysOfSwiftUI by Paul Hudson, Project 1), and currently I came across a problem that I haven’t been able to solve yet. Originally, the numberOfPeople section had a picker with below code, which I’m trying to change to a text field. Started by changing its @State property (@State private var numberOfPeople = 2) from 2 to empty string, and tried creating another computed property for people count. when the number of people text field is left empty, 0 doesn’t appear as default on the simulator on the amount per person section when I run the project, instead NaN appears as in the screenshot below. (Which makes me wonder if numberOfPeople converted successfully to an Integer through nil coalescing as below). Only time the project functions as it should is when I enter a value in the number of people text field. I’m not 100% sure where I went wrong with this, but any help will be greatly appreciated!!

struct ContentView: View {
    @State private var checkAmount = ""
    @State private var numberOfPeople = ""
    @State private var tipPercentage = 2
    
    let tipPercentages = [10,15,20,25,0]
    let allPeople = 2...100

    var totalPerPerson: Double {
        let peopleCount = Double(numberOfPeople) ?? 0
        let tipSelection = Double(tipPercentages[tipPercentage])
        let orderAmount = Double(checkAmount) ?? 0
        
        let tipValue = orderAmount / 100 * tipSelection
        let grandTotal = orderAmount + tipValue
        let amountPerPerson = grandTotal / peopleCount

        return amountPerPerson
    }
    
    var grandTotal: Double {
        let tipSelection = Double(tipPercentages[tipPercentage])
        let orderAmount = Double(checkAmount) ?? 0
        
        let tipValue = orderAmount / 100 * tipSelection
        let totalAmount = orderAmount + tipValue
        
        return totalAmount
    }
    
    var body: some View {
        NavigationView {
            Form {
                Section {
                    TextField("Amount", text: $checkAmount)
                        .keyboardType(.decimalPad)
                    
                    TextField("Number of people", text: $numberOfPeople)
                        .keyboardType(.numberPad)
                }
                
                Section(header: Text("How much tip do you want to leave?")) {
                    Picker("Tip percentage", selection: $tipPercentage) {
                        ForEach(0 ..< tipPercentages.count) {
                            Text("\(self.tipPercentages[$0])%")
                        }
                    }
                    .pickerStyle(SegmentedPickerStyle())
                }
                
                Section (header: Text("Total Amount")){
                    Text("$\(grandTotal, specifier: "%.2f")")
                }
                
                Section (header: Text("Amount Per Person")){
                    Text("$\(totalPerPerson, specifier: "%.2f")")
                }
            }
            .navigationBarTitle("WeSplit")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

(Original code for picker)
Picker("Number of people", selection: $numberOfPeople) {
        ForEach(2 ..< 100) {
            Text("\($0) people")

(Original code for people count)
let peopleCount = Double(numberOfPeople + 2)

project simulator

  • the issue is you can't divide something through 0. number of people is 0 but you need to check if number of people is 0 and return 0 maybe using a guard statement – Moritz Schaub May 06 '21 at 15:04

1 Answers1

2

What you're seeing is a result of trying to divide by zero. You can avoid that calculation by returning 0 from your totalPerPerson function if peopleCount is 0 before doing the division using something like this:

var totalPerPerson: Double {
    let peopleCount = Double(numberOfPeople) ?? 0
    let tipSelection = Double(tipPercentages[tipPercentage])
    let orderAmount = Double(checkAmount) ?? 0
    
    guard peopleCount > 0 else {
        return 0
    }
    
    let tipValue = orderAmount / 100 * tipSelection
    let grandTotal = orderAmount + tipValue
    let amountPerPerson = grandTotal / peopleCount

    return amountPerPerson
}

Keep in mind that with your new TextField, as opposed to the picker, even if you specify .decimalPad or .numberPad, there are still ways for the user to enter non-numerical values in those fields, so you'd probably want to put up an error if that happens (or, search here on SO for solutions about fields that only accept numbers). An example for such a TextField is specified in this solution

Moritz Schaub
  • 91
  • 1
  • 9
jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • 1
    Thank you so much for your help, I plugged in the guard statement like you said and it works perfect. Such a quick fix that was taking me forever to figure out. Much appreciated!! – Erick Osino May 07 '21 at 14:09