skip to Main Content

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:

enter image description here

3

Answers


  1. 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)
            }
        }
    }
    
    Login or Signup to reply.
  2. 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))
            }
        }
    }
    
    Login or Signup to reply.
  3. We don’t format strings ourselves 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. With UIKit most of us never bothered to listen to the locale changed notification to do it.

    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)")
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search