如何在不使用 .onAppear 的情况下使用 @EnvironmentObject 来初始化 @State?
How can I use @EnvironmentObject to initialize @State, without using .onAppear?
我正在关注 Stanfords 的 iOS 在线课程的 CS193p 开发应用程序。
我正在尝试执行 Assignment 6 (Memorize Themes.pdf).
当我在模拟器中 运行 我的应用程序时,出现以下致命错误:
线程 1:致命错误:在展开可选值时意外发现 nil
我想我可能理解为什么会出现此错误 - 因为 gamesBeingPlayed 被初始化为空,并且在 onAppear 中分配了正确的值,运行s AFTER body。
所以我的问题是:如何初始化@State private var gamesBeingPlayed?
- 我不能在 init() 中执行此操作,因为 @EnvironmentObject 是在视图构造函数调用后注入的
- 我也不能在 .onAppear{ } 中执行此操作,因为它在视图正文之后 运行。
import SwiftUI
struct ThemeChooserView: View {
@EnvironmentObject var themeStore: ThemeStore
@State private var gamesBeingPlayed: Dictionary<Theme.ID, EmojiMemoryGame> = [:]
var body: some View {
NavigationView {
List {
ForEach(themeStore.themes) { theme in
NavigationLink(destination: EmojiMemoryGameView(game: gamesBeingPlayed[theme.id]!)) {
// Here I get error: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
VStack(alignment: .leading) {
Text(theme.name)
.foregroundColor(theme.color)
.font(.title)
Text(themeCardsDescription(theme: theme))
}
}
}
}
.navigationTitle("Memorize")
}
.onAppear {
var games: Dictionary<Theme.ID, EmojiMemoryGame> = [:]
for theme in themeStore.themes {
games[theme.id] = EmojiMemoryGame(theme: theme)
}
gamesBeingPlayed = games
}
}
private func themeCardsDescription(theme: Theme) -> String {
let numberOrAll = theme.numberOfPairsOfCards == theme.emojis.count ? "All" : "\(theme.numberOfPairsOfCards)"
return numberOrAll + " pairs from \(theme.emojis.joined(separator: ""))"
}
}
如果我使用 nil 合并运算符,就像这样:
NavigationLink(destination: EmojiMemoryGameView(game: gamesBeingPlayed[theme.id] ?? EmojiMemoryGame(theme: themeStore.themes[0]))) {
...然后当我点击导航到所选的游戏主题时,它总是第一个:themeStore.themes[0]
。老实说,我不知道为什么。我认为 onAppear 应该在我点击列表中的视图导航时设置 gamesBeingPlayed。
请帮帮我
如果按假设回答问题
How can I use @EnvironmentObject to initialize @State, without using
.onAppear?
那么这是一种可能的方法 - 将所有内容移动到接受环境对象作为输入参数的内部视图(因为它已经存在于正文中),例如
struct ThemeChooserView: View {
@EnvironmentObject var themeStore: ThemeStore
var body: some View {
ThemeChooserViewImp(themeStore) // << here !!
}
private struct ThemeChooserViewImp: View {
@State private var gamesBeingPlayed: Dictionary<Theme.ID, EmojiMemoryGame> // << declare only
init(_ themeStore: ThemeStore) {
_gamesBeingPlayed = State(initialValue: ...) // << use themeStore
}
// ... other content here
}
}
我正在关注 Stanfords 的 iOS 在线课程的 CS193p 开发应用程序。 我正在尝试执行 Assignment 6 (Memorize Themes.pdf).
当我在模拟器中 运行 我的应用程序时,出现以下致命错误: 线程 1:致命错误:在展开可选值时意外发现 nil
我想我可能理解为什么会出现此错误 - 因为 gamesBeingPlayed 被初始化为空,并且在 onAppear 中分配了正确的值,运行s AFTER body。
所以我的问题是:如何初始化@State private var gamesBeingPlayed?
- 我不能在 init() 中执行此操作,因为 @EnvironmentObject 是在视图构造函数调用后注入的
- 我也不能在 .onAppear{ } 中执行此操作,因为它在视图正文之后 运行。
import SwiftUI
struct ThemeChooserView: View {
@EnvironmentObject var themeStore: ThemeStore
@State private var gamesBeingPlayed: Dictionary<Theme.ID, EmojiMemoryGame> = [:]
var body: some View {
NavigationView {
List {
ForEach(themeStore.themes) { theme in
NavigationLink(destination: EmojiMemoryGameView(game: gamesBeingPlayed[theme.id]!)) {
// Here I get error: "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
VStack(alignment: .leading) {
Text(theme.name)
.foregroundColor(theme.color)
.font(.title)
Text(themeCardsDescription(theme: theme))
}
}
}
}
.navigationTitle("Memorize")
}
.onAppear {
var games: Dictionary<Theme.ID, EmojiMemoryGame> = [:]
for theme in themeStore.themes {
games[theme.id] = EmojiMemoryGame(theme: theme)
}
gamesBeingPlayed = games
}
}
private func themeCardsDescription(theme: Theme) -> String {
let numberOrAll = theme.numberOfPairsOfCards == theme.emojis.count ? "All" : "\(theme.numberOfPairsOfCards)"
return numberOrAll + " pairs from \(theme.emojis.joined(separator: ""))"
}
}
如果我使用 nil 合并运算符,就像这样:
NavigationLink(destination: EmojiMemoryGameView(game: gamesBeingPlayed[theme.id] ?? EmojiMemoryGame(theme: themeStore.themes[0]))) {
...然后当我点击导航到所选的游戏主题时,它总是第一个:themeStore.themes[0]
。老实说,我不知道为什么。我认为 onAppear 应该在我点击列表中的视图导航时设置 gamesBeingPlayed。
请帮帮我
如果按假设回答问题
How can I use @EnvironmentObject to initialize @State, without using .onAppear?
那么这是一种可能的方法 - 将所有内容移动到接受环境对象作为输入参数的内部视图(因为它已经存在于正文中),例如
struct ThemeChooserView: View {
@EnvironmentObject var themeStore: ThemeStore
var body: some View {
ThemeChooserViewImp(themeStore) // << here !!
}
private struct ThemeChooserViewImp: View {
@State private var gamesBeingPlayed: Dictionary<Theme.ID, EmojiMemoryGame> // << declare only
init(_ themeStore: ThemeStore) {
_gamesBeingPlayed = State(initialValue: ...) // << use themeStore
}
// ... other content here
}
}