Post

Replies

Boosts

Views

Activity

SwiftData "Auto Inserts" array into ModelContext
Definitely one of the stranger quirks of SwiftData I've come across. I have a ScriptView that shows Line entities related to a Production, and a TextEnterScriptView that’s presented in a sheet to input text. I’m noticing that every time I type in the TextEditor within TextEnterScriptView, a new Line shows up in ScriptView — even though I haven’t explicitly inserted it into the modelContext. I'm quite confused because even though I’m only assigning a new Line to a local @State array in TextEnterScriptView, every keystroke in the TextEditor causes a duplicate Line to appear in ScriptView. In other words, Why is SwiftData creating new Line entities every time I type in the TextEditor, even though I’m only assigning to a local @State array and not explicitly inserting them into the modelContext? Here is my minimal reproducible example: import SwiftData import SwiftUI @main struct testApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Line.self, isAutosaveEnabled: false) } } } struct ContentView: View { @Environment(\.modelContext) var modelContext @Query(sort: \Production.title) var productions: [Production] var body: some View { NavigationStack { List(productions) { production in NavigationLink(value: production) { Text(production.title) } } .navigationDestination(for: Production.self) { production in ScriptView(production: production) } .toolbar { Button("Add", systemImage: "plus") { let production = Production(title: "Test \(productions.count + 1)") modelContext.insert(production) do { try modelContext.save() } catch { print(error) } } } .navigationTitle("Productions") } } } struct ScriptView: View { @Query private var lines: [Line] let production: Production @State private var isShowingSheet: Bool = false var body: some View { List { ForEach(lines) { line in Text(line.content) } } .toolbar { Button("Show Sheet") { isShowingSheet.toggle() } } .sheet(isPresented: $isShowingSheet) { TextEnterScriptView(production: production) } } } struct TextEnterScriptView: View { @Environment(\.dismiss) var dismiss @State private var text = "" @State private var lines: [Line] = [] let production: Production var body: some View { NavigationStack { TextEditor(text: $text) .onChange(of: text, initial: false) { lines = [Line(content: "test line", production: production)] } .toolbar { Button("Done") { dismiss() } } } } } @Model class Production { @Attribute(.unique) var title: String @Relationship(deleteRule: .cascade, inverse: \Line.production) var lines: [Line] = [] init(title: String) { self.title = title } } @Model class Line { var content: String var production: Production? init(content: String, production: Production?) { self.content = content self.production = production } }
1
0
49
Apr ’25
SwiftData Relationship Delete Not Working (SwiftData/PersistentModel.swift:359)
SwiftData delete isn't working, when I attempt to delete a model, my app crashes and I get the following error: SwiftData/PersistentModel.swift:359: Fatal error: Cannot remove My_App.Model2 from relationship Relationship - name: model2, options: [], valueType: Model2, destination: Model2, inverseName: models3, inverseKeypath: Optional(\Model2.models3) on My_App.Model3 because an appropriate default value is not configured. I get that it's saying I don't have a default value, but why do I need one? Isn't @Relationship .cascade automatically deleting the associated models? And onto of that, why is the error occurring within the do block, shouldn't it be caught by the catch, and printed? I have put together a sample project below. import SwiftUI import SwiftData @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Model3.self) } } } @Model class Model1 { var name: String @Relationship(deleteRule: .cascade, inverse: \Model2.model1) var models2: [Model2] = [] init(name: String) { self.name = name } } @Model class Model2 { var name: String var model1: Model1 @Relationship(deleteRule: .cascade, inverse: \Model3.model2) var models3: [Model3] = [] init(name: String, model1: Model1) { self.name = name self.model1 = model1 } } @Model class Model3 { var name: String var model2: Model2 init(name: String, model2: Model2) { self.name = name self.model2 = model2 } } struct ContentView: View { @Query var models1: [Model1] @Environment(\.modelContext) var modelContext var body: some View { NavigationStack { List(models1) { model1 in Text(model1.name) .swipeActions { Button("Delete", systemImage: "trash", role: .destructive) { modelContext.delete(model1) do { try modelContext.save() //SwiftData/PersistentModel.swift:359: Fatal error: Cannot remove My_App.Model2 from relationship Relationship - name: model2, options: [], valueType: Model2, destination: Model2, inverseName: models3, inverseKeypath: Optional(\Model2.models3) on My_App.Model3 because an appropriate default value is not configured. } catch { print(error.localizedDescription) } } } } .toolbar { Button("Insert", systemImage: "plus") { modelContext.insert(Model3(name: "model3", model2: Model2(name: "model2", model1: Model1(name: "model1")))) } } } } }
1
0
1k
Jan ’25
Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary
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. I'm using Xcode 16.2 and iPhone SE 2nd Gen. 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) } } } }
2
0
801
Jan ’25
Find the name of a CNContact's group (CNGroupName)
So I only recently uncovered the Contacts Framework through this video: https://youtu.be/sHKir2ZMk5Q. As such I'm not yet accustomed to the API. Basically my main problem is that I can't seem to find a way to access the name of the group a CNContact is in. The only support I can find is in Apple's own documentation, which isn't very helpful. if someone could point me in the right direction towards how to print the group name, I would be very grateful. My code is below, Cheers // ModelData.swift // B-Day import Foundation import Contacts import SwiftUI struct Contact: Identifiable { let id = UUID() let category: String let firstName: String let lastName: String let birthday: DateComponents? } func fetchAllContacts() async -> [Contact] { var contacts = [Contact]() let store = CNContactStore() let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactBirthdayKey, CNContactIdentifierKey, CNGroupNameKey] as [CNKeyDescriptor] let fetchRequest = CNContactFetchRequest (keysToFetch: keys) do { try store.enumerateContacts(with: fetchRequest, usingBlock: { contact, result in //this should print the name of the contact's group print(contact.groupName) contacts.append(Contact(category: contact.groupName, firstName: contact.givenName, lastName: contact.familyName, birthday: contact.birthday)) }) } catch { print("Error") } return contacts }
1
0
1k
Aug ’23
Trailing closure passed to parameter of type 'Visibility' that does not accept a closure
Hi All, I'm quite new to swift and am wondering why I am receiving a "Trailing closure passed to parameter of type 'Visibility' that does not accept a closure" error on the .toolbar{ line I Have Supplied My Code Below Thanks in Advance, Josh struct HomeView: View {     var body: some View {         Text("Home")             .toolbar{                 ToolbarItem(placement: .navigationBarLeading)                 Button(action: NavigationLink(destination: AccountView()), label: Image(systemName: "gearshape"))                 ToolbarItem(placement: .principal) { Text("Welcome").font(.title)                 }                 ToolbarItem(placement: .navigationBarTrailing)                 Button(action: NavigationLink(destination: AccountView()), label: Image(systemName: "person.circle"))             }             .navigationBarTitleDisplayMode(.inline)     } } struct HomeView_Previews: PreviewProvider {     static var previews: some View {         HomeView()     } }```
1
1
966
Jan ’23