在VStack Swift用户界面5中对成员“下标”的引用含糊不清

时间:2019-08-21 13:54:09

标签: swiftui swift5

我尝试在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()
}

在视图出现之前,我需要生成测验问题。我该怎么办?

1 个答案:

答案 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()
        }
    }

这样,您将为视图创建视图模型,并且在整个视图层次结构中都可以访问该视图模型。每次视图模型改变时,视图也会改变。