当用户在 AddProductionView 中单击
Save
时,我收到以下致命错误。
致命错误:在字典中发现“AnyHashable”类型的重复键。 这通常意味着该类型违反了 Hashable 的要求,或者 这样的字典的成员在插入后发生了变异。
据我所知,SwiftData 自动使其模型符合 Hashable,所以这应该不是问题。
我认为这与选择器有关,但我怎么也看不出是什么。
单击“保存”时,大约 75% 的情况下会出现此错误。
任何帮助将不胜感激......
这是我的代码:
import SwiftUI
import SwiftData
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: Character.self, isAutosaveEnabled: false)
}
}
}
@Model
final class Character {
var name: String
var production: Production
var myCharacter: Bool
init(name: String, production: Production, myCharacter: Bool = false) {
self.name = name
self.production = production
self.myCharacter = myCharacter
}
}
@Model
final class Production {
var name: String
init(name: String) {
self.name = name
}
}
struct ContentView: View {
@State private var showingSheet = false
var body: some View {
Button("Add", systemImage: "plus") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
AddProductionView()
}
}
}
struct AddProductionView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) var modelContext
@State var production = Production(name: "")
@Query var characters: [Character]
@State private var characterName: String = ""
@State private var selectedCharacter: Character?
var filteredCharacters: [Character] {
characters.filter { $0.production == production }
}
var body: some View {
NavigationStack {
Form {
Section("Details") {
TextField("Title", text: $production.name)
}
Section("Characters") {
List(filteredCharacters) { character in
Text(character.name)
}
HStack {
TextField("Character", text: $characterName)
Button("Add") {
let newCharacter = Character(name: characterName, production: production)
modelContext.insert(newCharacter)
characterName = ""
}
.disabled(characterName.isEmpty)
}
if !filteredCharacters.isEmpty {
Picker("Select your role", selection: $selectedCharacter) {
Text("Select")
.tag(nil as Character?)
ForEach(filteredCharacters) { character in
Text(character.name)
.tag(character as Character?)
}
}
.pickerStyle(.menu)
}
}
}
.toolbar {
Button("Save") { //Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion.
if let selectedCharacter = selectedCharacter {
selectedCharacter.myCharacter = true
}
modelContext.insert(production)
do {
try modelContext.save()
} catch {
print("Failed to save context: \(error)")
}
dismiss()
}
.disabled(production.name.isEmpty || selectedCharacter == nil)
}
}
}
}
我不确定崩溃的原因,因为(据我所知)不知道如何计算 PersistentModel 对象的哈希值,但我相信这与如何以及何时重新计算哈希值有关production
属性和/或
characters
属性中的元素可能会导致崩溃,因为某些内容以错误的顺序更新。处理创建两种不同类型模型的视图,然后处理它们之间的关系也可能非常棘手。因此,当我测试它时,下面的解决方案没有生成任何崩溃,它通过不使用任何类型的模型属性来简化整个解决方案,而是使用模型属性的属性,并在“保存”时以受控方式创建和插入所有新模型“按钮被按下。
struct AddProductionView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) var modelContext
@State private var production = ""
@State private var productionID: PersistentIdentifier?
@State private var characters: [String] = []
@State private var characterName: String = ""
@State private var selectedCharacter: String?
var body: some View {
NavigationStack {
Form {
Section("Details") {
TextField("Title", text: $production)
}
Section("Characters") {
List(characters, id: \.self) { character in
Text(character)
}
HStack {
TextField("Character", text: $characterName)
Button("Add") {
characters.append(characterName)
characterName = ""
}
.disabled(characterName.isEmpty || characters.contains(characterName))
}
if !characters.isEmpty {
Picker("Select your role", selection: $selectedCharacter) {
Text("Select")
.tag(nil as String?)
ForEach(characters, id: \.self) { character in
Text(character)
.tag(character as String?)
}
}
.pickerStyle(.menu)
}
}
}
.toolbar {
Button("Save") {
let production = Production(name: production)
modelContext.insert(production)
for name in characters {
let character = Character(name: name, production: production)
if let selectedCharacter, name == selectedCharacter {
character.myCharacter = true
}
}
do {
try modelContext.save()
} catch {
print("Failed to save context: \(error)")
}
dismiss()
}
.disabled(production.isEmpty || selectedCharacter == nil)
}
}
}
}