I am trying to use the NumberFormatter in a SwiftUI view but I am getting compiler errors. Here's my code:
import Foundation
import SwiftUI
struct AccountCard: View {
var netWorth: NetWorth
let formatter = NumberFormatter()
formatter.numberStyle = .currency
let investmentTotalString = formatter.string(for: netWorth.investmentTotal)
var body: some View {
VStack {
Text(netWorth.name)
Text(String(format: "%.2f", netWorth.investmentTotal))
Text(String(format: "%.2f", netWorth.cashBalance))
}
}
}
struct AccountCard_Previews: PreviewProvider {
static var previews: some View {
AccountCard(netWorth: netWorths[0])
}
}
What am I doing wrong?
Here's XCode showing the errors:
CodePudding user response:
SwiftUI does not allow statements in its setup such as formatter.numberStyle = .currency. There are places
in a view, such init(), or .onAppear{} for example, and of course any custom functions,
where such statements are allowed.
To achieve what you want you could try something like this:
struct AccountCard: View {
var netWorth: NetWorth
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
return formatter
}()
@State var investmentTotalString: String?
var body: some View {
VStack {
Text(netWorth.name)
Text(String(format: "%.2f", netWorth.investmentTotal))
Text(String(format: "%.2f", netWorth.cashBalance))
}
.onAppear {
investmentTotalString = formatter.string(for: netWorth.investmentTotal)
}
}
}
CodePudding user response:
Building on what workingdog wrote, creating NumberFormatter is an expensive operation, You should therefore make it e.g. static so it wouldn’t have to be recreated all the time. It’s also questionable whether you need State, you can always declare it as only var with getter.
struct AccountCard: View {
var netWorth: NetWorth
static let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
return formatter
}()
var investmentTotalString: String {
AccountCard.formatter.string(for: netWorth.investmentTotal)
}
var body: some View {
VStack {
Text(netWorth.name)
Text(String(format: "%.2f", netWorth.investmentTotal))
Text(String(format: "%.2f", netWorth.cashBalance))
}
}
}
CodePudding user response:
We don't format strings ourself anymore, we let SwiftUI do it for us. The reason for this is so it can update the labels on screen if the user changes their region settings.
We can simply tell SwiftUI what format we'd like:
struct AccountCard: View {
let netWorth: NetWorth
var body: some View {
VStack {
Text(netWorth.name)
Text(netWorth.investmentTotal, format: .currency(code: "USD"))
Text(netWorth.cashBalance, format: .currency(code: "USD"))
}
}
}
Or we can pass a formatter object in to the string interpolation:
let currencyFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
return formatter
}()
struct AccountCard: View {
let netWorth: NetWorth
var body: some View {
VStack {
Text(netWorth.name)
Text("$\(netWorth.investmentTotal, formatter: currencyFormatter)")
Text("$\(netWorth.cashBalance, formatter: currencyFormatter)")
}
}
}

