SwiftUI中ViewModel数据无法绑定到Table View的问题求助
问题:SwiftUI Table无法遍历ViewModel中的计算属性数组
我发现Apple官方文档及找到的Table使用教程(example 1、example 2)均基于非动态模型数组构建Table。我的ViewModel包含一个由函数和其他计算属性实现的计算属性数组userDataList,无法在View中编写代码让Table遍历该数组的每一项。
预期效果是生成一个包含5行(第1至第5年)、3列(Year、Annual Income、401k Balance)的Table,填充ViewModel中userDataList的对应数据。
原代码
struct ContentView: View { @StateObject var vm = ViewModel() var body: some View { VStack(spacing: 15){ TabView() { ProfileView() .tabItem { Image(systemName: "square.and.pencil") Text("Profile") } InvestView() .tabItem { Image(systemName: "dollarsign") Text("Tips") } } .environmentObject(vm) } } } struct ProfileView: View { var body: some View { Text("Hello, World!") } } //the ProfileView will eventually have a Form that allows the user to manipulate the values within the userData Published variable within the ViewModel struct EmployeeInfo: Codable, Identifiable { var id = UUID() var monthlyHours: Double var hourlyRateYear1: Double var hourlyRateYear2: Double var hourlyRateYear3: Double var hourlyRateYear4: Double var hourlyRateYear5: Double var startingBalance401k: Double var contribution: Double var balance401k: Double } struct InvestInfo: Codable, Identifiable { var id = UUID() var year: Int var annualIncome: Double var balance401k: Double } struct Year: Codable, Identifiable { var id = UUID() var year: Int } struct InvestView: View { @EnvironmentObject var vm: ViewModel private let currencyStyle = Decimal.FormatStyle.Currency(code:"USD") var body: some View { Table(of: vm.userDataList) { TableColumn("Years Until Retirement") { item in Text(item.year) } TableColumn("Annual Income") { item in Text(item.annualIncome), format: currencyStyle) } TableColumn("401k Balance") { item in Text(item.balance401k), format: currencyStyle) } } rows: { TableRow(Year(year: 1)) TableRow(Year(year: 2)) TableRow(Year(year: 3)) TableRow(Year(year: 4)) TableRow(Year(year: 5)) } } } class ViewModel: ObservableObject { @Published var userData: EmployeeInfo = EmployeeInfo(monthlyHours: 160.0, hourlyRateYear1: 15.0, hourlyRateYear2: 15.0, hourlyRateYear3: 17.0, hourlyRateYear4: 17.0, hourlyRateYear5: 19.0, startingBalance401k: 5000.0, contribution: 5000.0, balance401k: 10000.0) func calcAnnualEarnings(hourlyRate: Double) -> Double { return (userData.monthlyHours * hourlyRate) * 12 } var annualIncomeYear1: Double { calcAnnualEarnings(hourlyRate: userData.hourlyRateYear1) } var annualIncomeYear2: Double { calcAnnualEarnings(hourlyRate: userData.hourlyRateYear2) } var annualIncomeYear3: Double { calcAnnualEarnings(hourlyRate: userData.hourlyRateYear3) } var annualIncomeYear4: Double { calcAnnualEarnings(hourlyRate: userData.hourlyRateYear4) } var annualIncomeYear5: Double { calcAnnualEarnings(hourlyRate: userData.hourlyRateYear5) } func calc401k(princ: Double, deposits: Double) -> Double { let newRate = 10.0 let rn1 = 1+((newRate/100)/12) let comp = pow(rn1,12) let totPrinc = comp * princ return totPrinc + ((deposits/12) * (comp-1)/((newRate/100)/12)) } var balanceLine1: Double { return calc401k(princ: userData.startingBalance401k, deposits: userData.contribution) } var balanceLine2: Double { return calc401k(princ: balanceLine1, deposits: userData.contribution) } var balanceLine3: Double { return calc401k(princ: balanceLine2, deposits: userData.contribution) } var balanceLine4: Double { return calc401k(princ: balanceLine3, deposits: userData.contribution) } var balanceLine5: Double { return calc401k(princ: balanceLine4, deposits: userData.contribution) } var userDataList: [InvestInfo] { return [ InvestInfo(year: 1, annualIncome: annualIncomeYear1, balance401k: balanceLine1), InvestInfo(year: 2, annualIncome: annualIncomeYear2, balance401k: balanceLine2), InvestInfo(year: 3, annualIncome: annualIncomeYear3, balance401k: balanceLine3), InvestInfo(year: 4, annualIncome: annualIncomeYear4, balance401k: balanceLine4), InvestInfo(year: 5, annualIncome: annualIncomeYear5, balance401k: balanceLine5) ] } }
出现的错误
- 无法将类型'[InvestInfo]'转换为预期的参数类型'TableRow.TableRowValue.Type'(即'Year.Type')
- 调用初始化器无精确匹配
- 尾随闭包传递给不接受闭包的参数类型'KeyPath<TableRow.TableRowValue, String>'(即'KeyPath<Year, String>')
- 错误3重复出现
解决方案
问题根源
你混淆了SwiftUI Table的两种初始化逻辑:
Table(of: 类型)是用于静态行的写法,需要配合手动声明的TableRow- 直接绑定数据源数组的动态写法,不需要手动定义行,Table会自动遍历数组生成内容
你的代码既错误地把数组传入of:参数,又手动添加了无关的Year类型行,导致类型不匹配和语法错误。
修正后的InvestView代码
直接绑定vm.userDataList作为数据源,让Table自动遍历生成行,同时修正语法错误:
struct InvestView: View { @EnvironmentObject var vm: ViewModel private let currencyStyle = Decimal.FormatStyle.Currency(code: "USD") var body: some View { Table(vm.userDataList) { TableColumn("Years Until Retirement") { item in Text("\(item.year)") } TableColumn("Annual Income") { item in Text(item.annualIncome, format: currencyStyle) } TableColumn("401k Balance") { item in Text(item.balance401k, format: currencyStyle) } } } }
关键修正点
- 数据源绑定:用
Table(vm.userDataList)替代错误的Table(of: vm.userDataList),直接将计算属性数组作为数据源 - Int转字符串:
item.year是Int类型,需要用"\(item.year)"转成字符串后传入Text - 修正语法错误:原代码中
Text(item.annualIncome), format: currencyStyle)多了一个右括号,修正为正确的参数格式 - 移除静态行:不需要手动添加
TableRow,Table会自动遍历userDataList中的5个InvestInfo实例生成对应行
效果说明
修正后,Table会自动读取ViewModel中userDataList的每一项数据,生成5行3列的表格,且当userData中的参数变化时,计算属性userDataList会自动更新,表格内容也会实时刷新。
内容的提问来源于stack exchange,提问作者weekendwarrior
相关产品推荐
相关产品推荐

