SwiftUI:如何在子视图中仅创建一次非View对象
解决SwiftUI中仅在点击跳转时创建非View对象的问题
问题核心是当前代码里QuestionView会在HomeView首次渲染、以及highestNumber变化时重复初始化,导致Question被多次创建,不符合仅点击「Start」时创建一次的要求。要适配SwiftUI的声明式范式,关键是把非View对象的创建时机和视图跳转严格绑定,而不是依赖视图的初始化逻辑。
解决方案代码
修改HomeView:控制跳转时机与对象创建
struct HomeView: View { @State var highestNumber: Int = 12 @State private var currentQuestion: Question? var body: some View { NavigationStack { Picker("Highest Number", selection: $highestNumber) { ForEach(4...12, id: \.self) { Text(String($0)) } } .pickerStyle(.wheel) Button("Start") { // 仅在点击Start时创建Question实例 currentQuestion = Question(highestNumber) } // 只有currentQuestion非空时,才会触发跳转并初始化QuestionView .navigationDestination(item: $currentQuestion) { question in QuestionView(initialQuestion: question, highestNumber: highestNumber) } } } }
修改QuestionView:接收已创建的对象
struct QuestionView: View { let highestNumber: Int @State private var currentQuestion: Question init(initialQuestion: Question, highestNumber: Int) { print("QuestionView.init") self.highestNumber = highestNumber self._currentQuestion = State(initialValue: initialQuestion) } var body: some View { Text(currentQuestion.prompt) Button("I got it") { // 仅在点击按钮时生成新问题 currentQuestion = Question(highestNumber) } } }
逻辑说明
- 严格控制对象创建时机:
Question实例只会在「Start」按钮的点击闭包里创建,完全和用户操作绑定,避免了视图渲染时的意外初始化。 - 用状态驱动跳转:通过
navigationDestination(item:)关联currentQuestion状态,只有当该状态被设置(用户点击Start)时,才会初始化QuestionView并传递已创建好的Question。 - 移除不必要的绑定:
QuestionView不再接收highestNumber的绑定,而是接收初始值用于后续生成新问题,避免了外部状态变化触发视图重新初始化。
这样就能彻底解决Question重复创建的问题,同时符合SwiftUI声明式的状态驱动思维。
内容的提问来源于stack exchange,提问作者pquimo
相关产品推荐
相关产品推荐

