SwiftUI中如何将选中的汽车角落数据传递至ViewModel
解决视图与ViewModel间的角落数据传递问题
核心问题分析
当前CornerSetupScreen已获取到选中的corner,但CornerSetupDataViewModel无法接收该值,导致视图加载时无法自动调用populateValues加载对应配置数据。
解决方案步骤
1. 修改ViewModel初始化逻辑
让CornerSetupDataViewModel在初始化时接收corner参数,自动触发配置加载:
class CornerSetupDataViewModel: ObservableObject { @Published var corner: TestCorners // 改为非可选,初始化时必传 @Published var maxC2C: String = "50" @Published var maxNutHeight: String = "" @Published var sliderThickness: String = "" @Published var shaftDiameter: String = "" @Published var gasShock: Bool = false @Published var canister: Bool = false let userDefaults = UserDefaults.standard // 新增带corner参数的初始化方法 init(corner: TestCorners) { self.corner = corner populateValues() // 初始化时自动加载数据 } // 修改方法,直接使用实例的corner属性 func populateValues() { // 用空合并运算符避免强制解包崩溃,设置默认值 maxC2C = userDefaults.string(forKey: SetupKeyValues.maxC2C.rawValue + corner.rawValue) ?? "50" maxNutHeight = userDefaults.string(forKey: SetupKeyValues.maxNutHeight.rawValue + corner.rawValue) ?? "" sliderThickness = userDefaults.string(forKey: SetupKeyValues.sliderThickness.rawValue + corner.rawValue) ?? "" shaftDiameter = userDefaults.string(forKey: SetupKeyValues.shaftDiameter.rawValue + corner.rawValue) ?? "" gasShock = userDefaults.bool(forKey: SetupKeyValues.gasShock.rawValue + corner.rawValue) canister = userDefaults.bool(forKey: SetupKeyValues.canister.rawValue + corner.rawValue) } func saveValues() { // 直接使用实例的corner属性 userDefaults.set(maxC2C, forKey: SetupKeyValues.maxC2C.rawValue + corner.rawValue) userDefaults.set(maxNutHeight, forKey: SetupKeyValues.maxNutHeight.rawValue + corner.rawValue) userDefaults.set(sliderThickness, forKey: SetupKeyValues.sliderThickness.rawValue + corner.rawValue) userDefaults.set(gasShock, forKey: SetupKeyValues.gasShock.rawValue + corner.rawValue) userDefaults.set(canister, forKey: SetupKeyValues.canister.rawValue + corner.rawValue) print(maxC2C, corner.rawValue) } }
2. 在CornerSetupScreen中传入corner初始化ViewModel
通过自定义视图初始化方法,将corner传入ViewModel:
struct CornerSetupScreen: View { let corner: TestCorners @StateObject private var setupScreenVM: CornerSetupDataViewModel @State private var showAlert = false // 补充缺失的弹窗状态属性 // 自定义初始化方法 init(corner: TestCorners) { self.corner = corner self._setupScreenVM = StateObject(wrappedValue: CornerSetupDataViewModel(corner: corner)) } var body: some View { VStack { TestParameterSubView(parameterName: "Max Center-Center", parameterUnit: "in", parameterValue: $setupScreenVM.maxC2C) TestParameterSubView(parameterName: "Max Nut Height", parameterUnit: "in", parameterValue: $setupScreenVM.maxNutHeight) Button("Save") { setupScreenVM.saveValues() // 无需再传corner参数 showAlert = true } .alert(isPresented: $showAlert) { Alert( title: Text("Success"), message: Text("Shock data saved!") ) } } } }
3. 优化CornerSelectorSubView的参数传递
将selectedCorner改为常量(无需@State修饰,因为是外部传入值):
struct CornerSelectorSubView: View { @State var showThing = false let selectedCorner: TestCorners var body: some View { NavigationLink(destination: CornerSetupScreen(corner: selectedCorner)) { Text(selectedCorner.rawValue) .font(.largeTitle) .padding() .padding(.vertical) .overlay(RoundedRectangle(cornerRadius: 15) .stroke(Color.blue, lineWidth: 2)) } } }
关键优化点
- 避免强制解包:用
??为UserDefaults返回值设置默认值,防止无数据时崩溃 - 职责清晰:ViewModel初始化时直接绑定corner,自动触发数据加载
- 简化调用:saveValues方法不再需要外部传corner,直接使用内部存储的属性
内容的提问来源于stack exchange,提问作者bb4
相关产品推荐
相关产品推荐

