对 VStack Swift UI 5 中成员'subscript'的不明确引用



我尝试在VStack语句中运行一个函数,但它不起作用。当我在按钮(带有动作标签(中运行它时,它可以完美运行。如何将我的函数插入 VStack?

我声明了一个测验数据类:

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 生成测验是:

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

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

首先,您不能调用在VStack闭包中不返回some View的函数,因为该闭包不是正常的闭包,而是@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

使用结构 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()
}
}

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

最新更新