Please consider adding the ability to programatically download Premium and Enhanced voices. At the moment it is extremely inconvenient for our users, as they have to navigate to settings themselves to download voices. Our app relies heavily on SpeechSynthesis integration, and it would greatly benefit from this feature.
FB16307193
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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
}
}
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"))))
}
}
}
}
}
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Swift Student Challenge
SwiftUI
SwiftData
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)
}
}
}
}
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
}
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()
}
}```