我尝试在VStack语句中运行一个函数,但是它不起作用。当我在带有操作标签的按钮中运行它时,它可以完美运行。如何将功能插入VStack?
我声明一个QuizData类:
class QuizData: ObservableObject {
var allQuizQuestion: [QuizView] = [QuizView]()
let objectWillChange = PassthroughSubject<QuizData,Never>()
var currentQuestion: Int = 0 {
didSet {
withAnimation() {
objectWillChange.send(self)
}
}
}
}
我在这里使用它:
struct Quiz: View {
var continent: Continent
@EnvironmentObject var quizData: QuizData
var body: some View {
VStack
{
generateQuiz(continent: continent, quizData: self.quizData)
quizData.allQuizQuestion[quizData.currentQuestion]
}
.navigationBarTitle (Text(continent.name), displayMode: .inline)
}
}
func generateQuiz是:
func generateQuiz(continent: Continent, quizData: QuizData) -> Void {
var capital: [Capital]
var alreadyUse: [Int]
for country in CountryData {
if country.continentId == continent.id
{
alreadyUse = [Int]()
capital = [Capital]()
capital.append(CapitalData[country.id])
for _ in 1...3 {
var index = Int.random(in: 1 ... CapitalData.count - 1)
while alreadyUse.contains(index) {
index = Int.random(in: 1 ... CapitalData.count - 1)
}
capital.append(CapitalData[index])
}
capital.shuffle()
quizData.allQuizQuestion.append(QuizView(country: country, question: QuestionData[country.id], capital: capital))
}
}
quizData.allQuizQuestion.shuffle()
}
在视图出现之前,我需要生成测验问题。我该怎么办?
答案 0 :(得分:1)
首先,您不能在some View
闭包中调用不返回VStack
的函数,因为该闭包不是普通的闭包,而是@ViewBuilder
闭包:>
@functionBuilder
struct ViewBuilder {
// Build a value from an empty closure, resulting in an
// empty view in this case:
func buildBlock() -> EmptyView {
return EmptyView()
}
// Build a single view from a closure that contains a single
// view expression:
func buildBlock<V: View>(_ view: V) -> some View {
return view
}
// Build a combining TupleView from a closure that contains
// two view expressions:
func buildBlock<A: View, B: View>(_ viewA: A, viewB: B) -> some View {
return TupleView((viewA, viewB))
}
// And so on, and so forth.
...
}
这是一项Swift 5.1功能,可让您执行以下操作:
VStack {
Image(uiImage: image)
Text(title)
Text(subtitle)
}
使用它可以轻松地从其他几个视图创建一个视图。有关更多信息,请查看https://www.swiftbysundell.com/posts/the-swift-51-features-that-power-swiftuis-api
现在,如果遇到您的问题(如果我错了,请纠正我),您需要在视图显示生成某些数据之前调用一个函数。老实说,我更希望将数据从外部传递到视图(在创建视图之前创建数据)。但是,如果您确实需要它,可以执行以下操作:
struct ContentView: View {
private var values: [Int]! = nil
init() {
values = foo()
}
var body: some View {
List(values, id: \.self) { val in
Text("\(val)")
}
}
func foo() -> [Int] {
[0, 1, 2]
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
使用struct init并在视图创建时调用该函数。
编辑:要在下面回答您的评论,并且由于您使用的是@EnvironmentObject
,您可以执行以下操作:
class ContentViewModel: ObservableObject {
@Published var values: [Int]!
init() {
values = generateValues()
}
private func generateValues() -> [Int] {
[0, 1, 2]
}
}
struct ContentView: View {
@EnvironmentObject var contentViewModel: ContentViewModel
var body: some View {
List(contentViewModel.values, id: \.self) { val in
Text("\(val)")
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(ContentViewModel()) //don't forget this
}
}
#endif
在您的SceneDelegate
中:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(
rootView: ContentView()
.environmentObject(ContentViewModel()) //don't forget this
)
self.window = window
window.makeKeyAndVisible()
}
}
这样,您将为视图创建视图模型,并且在整个视图层次结构中都可以访问该视图模型。每次视图模型改变时,视图也会改变。