admin管理员组文章数量:1134587
I get the following fatal error when the user clicks Save
in AddProductionView.
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.
As far as I’m aware, SwiftData automatically makes its models conform to Hashable, so this shouldn’t be a problem.
I think it has something to do with the picker, but for the life of me I can’t see what.
This error occurs about 75% of the time when Save is clicked.
Any help would be greatly appreciated…
Here is my code:
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)
}
}
}
}
I get the following fatal error when the user clicks Save
in AddProductionView.
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.
As far as I’m aware, SwiftData automatically makes its models conform to Hashable, so this shouldn’t be a problem.
I think it has something to do with the picker, but for the life of me I can’t see what.
This error occurs about 75% of the time when Save is clicked.
Any help would be greatly appreciated…
Here is my code:
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)
}
}
}
}
Share
Improve this question
asked Jan 7 at 22:13
The-WolfThe-Wolf
436 bronze badges
5
|
1 Answer
Reset to default 1I am not sure about the reason for the crash since it's not known (to my knowledge) how the hash value is calculated for PersistentModel objects but I believe the crash is related to how and when the hash value gets re-calculated for either the production
property and/or the elements in the characters
property that can lead to a crash because something gets updated in the wrong order.
It can be quite tricky to handle a view where two different types of models gets created and then handle a relationship between them without running into issues. So the below no-thrills solution, that has not generated any crashes when I tested it, simplified the whole solution by not working with any kind of model properties and instead uses properties for the model attributes and creates and inserts all new models in a controlled manner when the "Save" button is pressed. In this way everything is very local (in-memory) to the view while editing.
struct AddProductionView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) var modelContext
@State private var productionName = ""
@State private var characterNames: [String] = []
@State private var characterName: String = ""
@State private var selectedCharacter: String?
var body: some View {
NavigationStack {
Form {
Section("Details") {
TextField("Title", text: $productionName)
}
Section("Characters") {
List(characterNames, id: \.self) { character in
Text(character)
}
HStack {
TextField("Character", text: $characterName)
Button("Add") {
characterNames.append(characterName)
characterName = ""
}
.disabled(characterName.isEmpty || characterNames.contains(characterName))
}
if !characterNames.isEmpty {
Picker("Select your role", selection: $selectedCharacter) {
Text("Select")
.tag(nil as String?)
ForEach(characterNames, id: \.self) { character in
Text(character)
.tag(character as String?)
}
}
.pickerStyle(.menu)
}
}
}
.toolbar {
Button("Save") {
let production = Production(name: productionName)
modelContext.insert(production)
for name in characterNames {
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(productionName.isEmpty || selectedCharacter == nil)
}
}
}
}
本文标签: swiftFatal error Duplicate keys of type 39AnyHashable39 were found in a DictionaryStack Overflow
版权声明:本文标题:swift - Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736771722a1952121.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Production
with the samename
? – Paulw11 Commented Jan 8 at 5:12name
property in Production so it should be possible to have duplicates. – Joakim Danielson Commented Jan 8 at 8:16