You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在@AppStorage中无法将String转换为Int的技术求助

解决@AppStorage字符串转数值类型并实现乘法运算的问题

核心解决方案

直接将@AppStorage的存储类型改为数值类型(推荐用Double支持小数薪水,若只需整数可换Int),同时给TextField做字符串与数值的双向绑定转换,最后通过计算属性实时实现乘法运算。

修改后的完整代码

import SwiftUI

struct HomeView: View {
    var body: some View {
        NavigationView {
            ExtractedView()
        }
    }
}

struct ExtractedView: View {
    @State var monthString = Date().getMonthString().lowercased().capitalized
    // 用Double存储输入数值,替代原String类型
    @State private var salaryPh: Double = 0.0
    @State private var hoursPm: Double = 0.0
    
    // 直接将@AppStorage定义为Double类型,默认值设为0.0
    @AppStorage("SALARY_KEY") var savedSalary: Double = 0.0
    @AppStorage("HOURS_KEY") var savedHoursPm: Double = 0.0
    
    // 计算属性:实时计算月薪并格式化
    var monthlySalary: String {
        let total = salaryPh * hoursPm
        return String(format: "%.2f", total)
    }
    
    var body: some View {
        ZStack {
            BackgroundView()
            CalendarView()
            
            RoundedRectangle(cornerRadius: 40)
                .frame(width: 225, height: 100)
                .foregroundColor(.blue)
                .offset(y: 190)
            
            VStack(alignment: .center, spacing: 13) {
                Text("Your netto-salary per hour")
                    .foregroundColor(Color.white)
                    .font(Font.system(size: 23, design: .rounded))
                    .fontWeight(.light)
                // 自定义绑定,实现Double与String双向转换
                TextField("Salary", text: Binding(
                    get: { String(format: "%.2f", salaryPh) },
                    set: {
                        if let value = Double($0) {
                            salaryPh = value
                        }
                    }
                ))
                    .frame(width: 100, height: 50)
                    .background(.black)
                    .opacity(0.5)
                    .foregroundColor(Color.white)
                    .multilineTextAlignment(.center)
                    .font(.system(.body, design: .monospaced))
                    .overlay (
                        RoundedRectangle(cornerRadius: 15)
                            .stroke(Color.blue, lineWidth: 4)
                    )
                    .onChange(of: salaryPh) { newValue in
                        savedSalary = newValue
                    }
                    .onAppear {
                        salaryPh = savedSalary
                    }
            }
            .offset(y: -150)
            
            
            VStack(alignment: .center, spacing: 13) {
                Text("Hours in this month")
                    .foregroundColor(Color.white)
                    .font(Font.system(size: 23, design: .rounded))
                    .fontWeight(.light)
                // 同样的自定义绑定处理小时数
                TextField("Hours", text: Binding(
                    get: { String(format: "%.2f", hoursPm) },
                    set: {
                        if let value = Double($0) {
                            hoursPm = value
                        }
                    }
                ))
                    .foregroundColor(Color.white)
                    .frame(width: 100, height: 50)
                    .background(.black)
                    .opacity(0.5)
                    .multilineTextAlignment(.center)
                    .font(.system(.body, design: .monospaced))
                    .overlay (
                        RoundedRectangle(cornerRadius: 15)
                            .stroke(Color.blue, lineWidth: 4)
                    )
                    .onChange(of: hoursPm) { newValue in
                        savedHoursPm = newValue
                    }
                    .onAppear {
                        hoursPm = savedHoursPm
                    }
            }
            .offset(y: -20)
        
            VStack(spacing: 20) {
                Text("In \(monthString) i make:")
                    .foregroundColor(Color.white)
                    .font(Font.system(size: 23, design: .rounded))
                    .fontWeight(.light)
                // 显示计算后的月薪
                Text(monthlySalary)
                    .foregroundColor(.white)
                    .font(.system(size: 30, design: .monospaced))
                    .fontWeight(.bold)
            }
            .offset(y: 165)
        }
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        HomeView()
    }
}

// 补充原项目缺失的扩展和视图,避免编译错误
extension Date {
    func getMonthString() -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "MMMM"
        return formatter.string(from: self)
    }
}

struct BackgroundView: View {
    var body: some View {
        Color.black.ignoresSafeArea()
    }
}

struct CalendarView: View {
    var body: some View {
        EmptyView() // 替换为你的实际日历视图
    }
}

关键修改说明

  • @AppStorage类型优化:直接将存储变量定义为Double,@AppStorage原生支持数值类型存储,无需通过字符串中转,避免转换错误。
  • TextField双向绑定:通过自定义Binding实现数值与字符串的转换,既保证输入框显示友好的字符串格式,又能将输入值转为数值类型处理。
  • 实时计算逻辑:新增计算属性monthlySalary,用salaryPh * hoursPm实时计算月薪,并格式化显示为带2位小数的字符串。
  • 数据同步:通过onChange监听数值变化,自动同步到@AppStorage;onAppear时从@AppStorage加载保存的数值到本地状态。

如果只需要整数运算,只需把所有Double替换为Int,并将格式化字符串改为"%d"即可。

内容的提问来源于stack exchange,提问作者Deniss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:00:38