< Adding a segmented control for tip percentages WeSplit: Wrap up >

# Calculating the total per person

Paul Hudson    @twostraws

So far the final section has shown a simple text view with whatever check amount the user entered, but now it’s time for the important part of this project: we want that text view to show how much each person needs to contribute to the payment.

There are a few ways we could solve this, but the easiest one also happens to be the cleanest one, by which I mean it gives us code that is clear and easy to understand: we’re going to add a computed property that calculates the total.

This needs to do a small amount of mathematics: the total amount payable per person is equal to the value of the order, plus the tip percentage, divided by the number of people.

But before we can get to that point, we first need to pull out the values for how many people there are, what the tip percentage is, and the value of the order. That might sound easy, but there are some small wrinkles:

• As you’ve already seen, `numberOfPeople` is off by 2 – when it stores the value 3 it means 5 people.
• The `tipPercentage` integer stores an index inside the `tipPercentages` array rather than the actual tip percentage.
• The `checkAmount` property is a string that the user entered, which might be a valid number like 20, it might be a string like “fish”, or it might even be empty.

So, we’re going to create a new computed property called `totalPerPerson` that will be a `Double`, and it will start by getting those three values above.

First, add the computed property itself, just before the `body` property:

``````var totalPerPerson: Double {
// calculate the total per person here
return 0
}``````

That sends back 0 so your code doesn’t break, but we’re going to replace the `// calculate the total per person here` comment with our calculations.

Next, we can figure out how many people there are by reading `numberOfPeople` and adding 2 to it. Remember, this thing has the range 2 to 100, but it counts from 0, which is why we need to add the 2.

So, start by replacing `// calculate the total per person here` with this:

``let peopleCount = Double(numberOfPeople + 2)``

You’ll notice that converts the resulting value to a `Double` so we can add everything up and divide it without losing accuracy.

Next we need to figure out the actual tip percentage. Our `tipPercentage` property stores the value the user chose, but that’s actually just a position in the `tipPercentages` array. As a result, we need to look in `tipPercentages` to figure out what they chose, and again convert it to a `Double` so we can keep all our precision – add this below the previous line:

``let tipSelection = Double(tipPercentages[tipPercentage])``

The final number we need for our calculation is the value of their check. Now, if you remember this is actually a string right now, because it’s used as a two-way binding to a text field. Although we wrote code to show only a decimal pad keyboard, there’s nothing stopping creative users from entering invalid values in there, so we need to be careful how we handle it.

What we want to have is another `Double` of the check amount. We actually have a string that may or may not contain a valid `Double`: it might be 22.50, it might be an empty string, or it might be the complete works of Shakespeare. It’s a string – it can be pretty much anything.

Fortunately, Swift has a simple way of converting a string to a `Double`, and it looks like this:

``````let stringValue = "0.5"
let doubleValue = Double(stringValue)``````

That might look easy enough, but there’s a catch: the type of `doubleValue` ends up being `Double?` and not `Double` – yes, it’s an optional. You see, Swift can’t know for sure that the string contains something that can be safely be converted into a `Double`, so it uses optionality: if the conversion was successful then our optional will contain the resulting value, but if the string was something invalid (“Fish”, the complete works of Shakespeare, etc) then the optional will be set to nil.

There are several ways we could handle the optionality here, but the easiest is to use the nil coalescing operator, `??`, to ensure there’s always a valid value.

Please add this code to the `totalPerPerson` computed property, below the previous two:

``let orderAmount = Double(checkAmount) ?? 0``

That will attempt to convert `checkAmount` into a `Double`, but if that fails for some reason will use 0 instead.

Now that we have our three input values, it’s time do our mathematics. This takes another three steps:

• We can calculate the tip value by dividing `orderAmount` by 100 and multiplying by `tipSelection`.
• We can calculate the grand total of the check by adding the tip value to `orderAmount`.
• We can figure out the amount per person by dividing the grand total by `peopleCount`.

Once that’s done, we can return the amount per person and we’re done.

Replace `return 0` in the property with this:

``````let tipValue = orderAmount / 100 * tipSelection
let grandTotal = orderAmount + tipValue
let amountPerPerson = grandTotal / peopleCount

return amountPerPerson``````

If you’ve followed everything correctly your code should look like this:

``````var totalPerPerson: Double {
let peopleCount = Double(numberOfPeople + 2)
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
}``````

Now that `totalPerPerson` gives us the correct value, we can change the final section in our table so it shows the correct text.

Replace this:

``````Section {
Text("\$\(checkAmount)")
}``````

With this:

``````Section {
Text("\$\(totalPerPerson)")
}``````

Try running the app now, and see what you think. You should find that because all the values that make up our total are marked with `@State`, changing any of them will cause the total to be recalculated automatically.

Hopefully you’re now seeing for yourself what it means that SwiftUI’s views are a function of their state – when the state changes, the views automatically update to match.

Before we’re done, we’re going to fix a small issue with our interface, which is the way the total price is shown. We’re using a `Double` for our amount calculations, which means Swift is giving us much more precision than we need – we expect to see something like \$25.50, but instead see \$25.500000.

We can solve this by using a neat string interpolation feature that SwiftUI adds: the ability to decide how a number ought to be formatted inside the string. This actually dates way back to the C programming language, so the syntax is a little odd at first: we write a string called a specifier, giving it the value "%.2f”. That’s C’s syntax to mean “a two-digit floating-point number.”

Very roughly, “%f” means “any sort of floating-point number,” which in our case will be the entire number. An alternative is “%g”, which does the same thing except it removes insignificant zeroes from the end – \$12.50 would be written as \$12.5. Putting “.2” into the mix is what asks for two digits after the decimal point, regardless of what they are. SwiftUI is smart enough to round those intelligently, so we still get good precision.

You can read more about these C-style format specifiers on Wikipedia: https://en.wikipedia.org/wiki/Printf_format_string – we aren’t going to any others, so it’s just there if you want to satisfy your curiosity!

Anyway, we want the amount per person to use our new format specifier, so please modify the total text view to this:

``Text("\$\(totalPerPerson, specifier: "%.2f")")``

Now run the project for the last time – we’re done!

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

 < Adding a segmented control for tip percentages WeSplit: Wrap up >