SwiftUI 绑定 bool 外部视图 - “访问安装在视图之外的状态值”

lac*_*her 6 swift swiftui

我试图在一个简单的测验(例如示例)中将逻辑与用户界面分开。但当我回答完问题后,我正在努力思考如何离开。

在 Xcode 12 中我收到错误:

访问安装在视图之外的状态值。这将导致 Binding 的初始值恒定并且不会更新。

我从其他答案中看到@State只能在struct中使用,建议发布。但我似乎无法弄清楚如何使用已发布的属性与其绑定而不是“安装在视图上”

class ViewModel: ObservableObject {
    @Published var currentQuestion: String!

    private var questions = ["one", "two", "three"]
    private var index = 0

    init() {
        currentQuestion = questions[index]
    }

    func button(title: String) -> some View {
        Button(action: { [self] in
            if index < questions.count {
                index += 1
                currentQuestion = questions[index]
            } else {
                print("go to results view")
            }
        }) {
            Text(title)
        }
    }
}

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                viewModel.button(title: viewModel.currentQuestion)
            }
        }
    }
}

struct ResultsView: View {
    var body: some View {
        Text("Results")
    }
}
Run Code Online (Sandbox Code Playgroud)

任何关于采取什么方法的建议将不胜感激!

paw*_*222 6

您可以尝试将所有逻辑放在ViewModel

class ViewModel: ObservableObject {
    @Published var currentQuestion: String!
    @Published var showResults = false

    private var questions = ["one", "two", "three"]
    private var index = 0

    init() {
        currentQuestion = questions[index]
    }
    
    func nextQuestion() {
        if index < questions.count {
            index += 1
            currentQuestion = questions[index]
        } else {
            showResults = true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和视图中的 UI 组件(例如按钮):

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                Text(viewModel.currentQuestion)
                Button(action: viewModel.nextQuestion) {
                    Text("Next")
                }
            }
            // if viewModel.showResults == true -> navigate to results
            .background(NavigationLink(destination: ResultsView(), isActive: $viewModel.showResults) { EmptyView() } .hidden())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,您使用了ResultsViewa NavigationLink,但您可以轻松地用结果替换当前视图。演示由您决定。