Coding
Split my Meal
An even split punishes whoever ordered the salad. This iOS app apportions tax and tip to what each person actually had, and keeps the meal afterwards.
- Role
- Sole author: design, SwiftUI and SwiftData implementation, App Store submission
- Years
- Built with
- Swift, SwiftUI, SwiftData, MapKit, Xcode, GitHub Actions
Even is not fair
Dividing a bill by the number of people is the default because it is the only thing you can do in your head. It is also wrong whenever the table ordered differently, and the unfairness compounds: the person who had a salad pays a share of the tax and the tip on someone else's steak.
The correct version is not complicated, just tedious. Total each person's own items, allocate the shared charges in proportion to those totals, and you have four different numbers instead of one. That is the entire product.
What makes it usable is the entry, not the arithmetic. Getting a real table of items and people into a phone quickly is the actual design problem. Items carry a category. The input components were built to be typed into fast, which is not the same as being built to look tidy in a screenshot.
A year after the first app
This came a year after my first iOS app, and the difference is mostly organisational. The first was views with logic in them. This one separates screens, reusable input components, and computation utilities, so the splitting maths is testable independently of anything on screen.
public extension NumberFormatter {
static let twoDigitFormat: NumberFormatter = {
let nf = NumberFormatter()
nf.numberStyle = .decimal
nf.minimumFractionDigits = 4
nf.maximumFractionDigits = 4
return nf
}()
func string(from obj: Double, missing: String = "") -> String {
string(from: NSNumber(value: obj)) ?? missing
}
}Formatter.swiftShreyasdbz/split-my-meal · SplitMyMeal-Prod-A/Lib/
Every amount in the app renders through this one formatter, which is named for two digits and configured for four.
Persistence changed too. The first app used Core Data; this one uses SwiftData, with receipt photos stored as external attachments so an image does not sit inside the record it belongs to. Local place search keeps the restaurant with the meal, which is what makes a saved meal recognisable six months later. A row of numbers is not.
Everything stays on the device. No account, no server, and nothing collected.
A wrong label is a wrong answer
The update after release fixed one thing: the tax and tip labels were swapped in the splits view.
7281e1dlabels
@@ -53,14 +53,14 @@ .fontWeight(.light)}HStack{removed: Text("Tip")added: Text("Tax") .fontWeight(.regular) Spacer() Text(getMealTaxText(meal: meal)) .fontWeight(.light)}HStack{removed: Text("Tax")added: Text("Tip") .fontWeight(.regular) Spacer() Text(getMealTipText(meal: meal))SplitsModal.swiftShreyasdbz/split-my-meal · SplitMyMeal-Prod-A/Screens/SplitsModal/
The whole update. Both amounts were already right; each was standing under the other one's heading.
The computed numbers were correct the whole time. But an app whose only job is to be trusted with arithmetic cannot show a correct total under the wrong heading, because nobody re-derives the answer to check. The display was the product, and it was wrong.