SwiftData

RSS for tag

SwiftData is an all-new framework for managing data within your apps. Models are described using regular Swift code, without the need for custom editors.

SwiftData Documentation

Posts under SwiftData tag

508 Posts
Sort by:
Post not yet marked as solved
2 Replies
1.1k Views
Hey there, for my recent projects I used CoreData for persistence. One nice feature I use all the time is the ability to create a child context for editing operations. When editing an entity in a form presented as a sheet, the changes made are only saved into the main context/parent context if the child context (I call this the editing context) is saved. Therefore dismissing an editing view results in destroying the child context and all the changes are discarded. Likewise when saving in the editing view, the changes will be proceeded to the parent context and persisted. Is there any possibility to get the same or equivalent behavior when using SwiftData. Or is there another way to model this kind of cases? All the best from Cologne, Germany!
Posted
by
Post not yet marked as solved
11 Replies
2.5k Views
Is there a way to use SwiftData without automatic iCloud sync? I’d like to do that manually using my own CloudKit solution or CKSyncEngine. SwiftData automatically picks up any CloudKit containers though and I have not seen an option to disable this behavior. Setting cloudKitContainerIdentifier to nil does still pick the first available CloudKit container. Just in case this is a bug: FB12276416 Sample: let configuration = ModelConfiguration(cloudKitContainerIdentifier: nil) let modelContainer = try! ModelContainer(for: [GamesCollection.self], configuration) print(modelContainer.configurations) // [SwiftData.ModelConfiguration(url: …, name: …, sharedAppContainerIdentifier: …, cloudKitContainerIdentifier: Optional("iCloud.CloudKit.com.+++")
Posted
by
Post not yet marked as solved
1 Replies
1.6k Views
Just for grins, I tried running the SwiftData generation tool on the existing Core Data model of a non-trivial app I've worked on for a decade or so. It's pretty substantial, and uses some more advanced features, so it seemed like an interesting test case. One of the warnings that was not reported by the UI, but which showed up in the generated code was quite a few instances of this: Entity inheritance on entity Bar (parent class Foo) is unsupported in SwiftData. Now that I'm looking at the code examples more carefully, I see an awful lot of final class, which maybe should have raised a red flag sooner. But to the best of my recollection, none of the sessions outright said that inheritance (was or) was not supported. Core Data has supported this functionality for a long time (maybe since the beginning). Assuming that this isn't supported in this first seed, are there plans to provide this functionality in the future? By the launch of iOS 17? (For the record, this model has 93 entities, of which 34 have parent entities. 14 are abstract, which I gather is also not supported. 3 of the entities are both abstract and have parent entities.)
Posted
by
610
Post not yet marked as solved
4 Replies
1.7k Views
Hi, in the session the following is mentioned: If a trip already exists with that name, then the persistent back end will update to the latest values. This is called an upsert. An upsert starts as an insert. If the insert collides with existing data, it becomes an update and updates the properties of the existing data. Nevertheless, if I have a unique constraint on an (String) attribute and try to insert the same again, I end up in the debugger in the generated getter of the attribute: @Attribute(.unique) public var name: String { get { _$observationRegistrar.access(self, keyPath: \.name) return self.getValue(for: \.name) // <- here } EXC_BREAKPOINT (code=1, subcode=0x1a8d6b724) Am I missing something? If this is expected behaviour, how should I prevent this crash (other than checking for uniqueness before every insert)? Thank you! Cheers, Michael
Posted
by
Post not yet marked as solved
4 Replies
2.8k Views
Hey, I am trying to save an enum in my model with SwiftData but getting a weird error message I do not understand at the moment, and I am pretty sure I am missing something here. public enum URLScheme: String, Codable { case https case http } @Model public class MyModel { public var urlScheme: URLScheme } When I try to save the model I get the following error message in the console: error: Row (pk = 1) for entity 'MyModel' is missing mandatory text data for property 'https' I was wondering if I need to tell SwiftData how to save my enum ? My assumption was that I can save any enum if it conforms to Codable. Am I doing something wrong here or is this a beta bug ? Thanks a lot for helping
Posted
by
Post not yet marked as solved
1 Replies
771 Views
I am trying to create a document-based (macOS) app using SwiftUI and SwiftData. I'm trying to set up XCTests to validate my model behaviors. Clearly, I need to set up a container in my test class for my model objects. Failing to do so shows that SwiftData is trying: my app launches into the New Document dialog; if I dismiss it, the app fails with a "failed to find an active container" for my model object. Any pointer on setting up a container and context within XCTest is welcome. TIA
Posted
by
Post not yet marked as solved
3 Replies
1.4k Views
The 'unique' attribute is a really nice feature, BUT. In some of my apps, the unique identifier for an object is a combination of multiple attributes. (Example: a book title is not unique, but a combination of book title and author list is.) How do I model this with SwiftData? I cannot use @Attribute(.unique) on either the title OR the author list, but I want SwiftData to provide the same "insert or update" logic. Is this possible?
Posted
by
Post not yet marked as solved
2 Replies
765 Views
I may not be understanding this right, but when trying to use the new @Environment for what was previously @EnvironmentObject I am unable to use a NavigationPath in a NavigationStack: @Observable class AppData { var presented: NavigationPath = NavigationPath() } NavigationStack(path: appData.$presented) {... Value of type 'AppData' has no member '$presented' Cannot convert value of type 'NavigationPath' to expected argument type 'Binding' Moving the $ to the front or removing it does nothing either.
Posted
by
Post not yet marked as solved
1 Replies
969 Views
I can't find the method to create ModelContainer that appears in the video at 8: 52. The code in the video is as follows: let container = ModelContainer( for: Trip.self, migrationPlan: SampleTripsMigrationPlan.self ) This method doesn't seem to exist in Xcode15. I found other method to create ModelContainer using Schema and Schema MigrationPlan in Xcode15. public convenience init(for givenSchema: Schema, migrationPlan: (SchemaMigrationPlan.Type)? = nil, _ configurations: ModelConfiguration...) throws And I tried to create a Schema to use this method, like this: let container = try! ModelContainer(for: .init([Person.self]), migrationPlan: MigrationPlan.self) But an error occurred during runtime SwiftData/ModelContext.swift:177: Fatal error: Container does not have any data stores SwiftDataDemoApp.swift How to create a ModelContainer with [PersistentModel] and SchemaMigrationPlan ? Xcode Version: 15.0 beta (15A5160n) MacOS: 13.3.1 (a) (22E772610a)
Posted
by
Post not yet marked as solved
3 Replies
1.2k Views
I am trying to use SwiftData to perform a Query based on the name of the actor, which is inside a movie model. Here is the Movie model. @Model final class Movie { var title: String var year: Int @Relationship(.noAction, inverse: \Actor.movies) var actors: [Actor] = [] init(title: String, year: Int) { self.title = title self.year = year } } Here is my actual Query: _movies = Query(filter: #Predicate { $0.actors.contains(where: { $0.name.contains(actorName) }) }) But it returns nothing, even though I am passing actorName which exists in the movie.
Posted
by
Post not yet marked as solved
1 Replies
737 Views
Is it possible to either query a single instance or instruct SwiftData that there should only be a single instance in my model? I have the following basic structure in a lot of my views to query the first element and use it to display data. There is always only one instance, it is by design. @Query private var waterData: [WaterData] var body: some View { if let data = waterData.first { EmptyView() } else { ContentUnavailableView("Content unavailable", systemImage: "xmark.circle") } } Is there a way to reduce the boilerplate of if let data = ... in each view?
Posted
by
Post not yet marked as solved
6 Replies
1.4k Views
When I update a variable inside my model that is marked @Transient, my view does not update with this change. Is this normal? If I update a non-transient variable inside the model at the same time that I update the transient one, then both changes are propagated to my view. Here is an example of the model: @Model public class WaterData { public var target: Double = 3000 @Transient public var samples: [HKQuantitySample] = [] } Updating samples only does not propagate to my view.
Posted
by
Post not yet marked as solved
3 Replies
643 Views
In the "old" world we could define a model property as an integer (e.g. "Integer 64") and then have the actual class representing that model define the property as an enum instead and have getters/setters using methods such as primitiveValue(forKey:) When migrating to use SwiftData I changed the model to be an actual enum type and even though the underlying type of the enum is an integer and therefore supported by the primitive storage it requires me to use Codable on the enum instead and doing so makes it incompatible with the old CoreData model. Does anyone have any ideas or workarounds here or do you feel it is a bug and should be reported? enum FooType: Int64 { case awesome case super } @Model final class Note { var type: FooType // ERROR }
Posted
by
Post not yet marked as solved
2 Replies
2.3k Views
How do I delete all the rows in an entity and/or delete the entity all together in SwiftData? Here is a function I used to delete an entity in core data for reference. class func deleteEntity(entity: String) { let fetchRequest1: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entity)//entity.fetchRequest() let batchDeleteRequest1 = NSBatchDeleteRequest(fetchRequest: fetchRequest1) _ = try? PersistanceController.shared.container.viewContext.execute(batchDeleteRequest1) print("Deleting coredata entity: \(entity)") }
Posted
by
Post not yet marked as solved
2 Replies
654 Views
I used Schema and MigrationPlan to initialize the Model Container. SwiftDataDemoApp.swift Then I modified the Schema and created a MigrationStage through the custom method, which was configured in the stages array of the SchemaMigrationPlan. Models.swift But when I run the app, I don't receive the willMigrate and didMigrate callbacks Xcode Version: 15.0 beta (15A5160n) MacOS: 13.3.1 (a) (22E772610a)
Posted
by
Post not yet marked as solved
0 Replies
630 Views
In CoreData with CloudKit mirroring, only lightweight migration is allowed to database migration. Heavyweight (custom) migration are not recommended. Are the rules also applied to SwiftData with CloudKit mirroring? (I assume it is true, because cloudkit backend properties are not changed even if SwfitData released)
Posted
by
Post marked as solved
10 Replies
2.7k Views
Overview I have 2 models: Deparment and Student Each Department can contain multiple students Each Student can only be in one Department I have DepartmentList, tapping on the department should take it to the StudentList which lists all students in the department Problem When I use Query in StudentList to filter only students for a specific department id, no students are shown. Questions: What should I do to list the students in a department? (see complete code below). let filter = #Predicate<Student> { student in student.department?.id == departmentID } let query = Query(filter: filter, sort: \.name) _students = query Complete code App @main struct SchoolApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: [Department.self, Student.self]) } } Department import Foundation import SwiftData @Model class Department { var id: UUID var name: String var students: [Student] init( id: UUID, name: String, students: [Student] = [] ) { self.id = id self.name = name self.students = students } } Student import Foundation import SwiftData @Model class Student { var id: UUID var name: String @Relationship(inverse: \Department.students) var department: Department? init( id: UUID, name: String, department: Department? = nil ) { self.id = id self.name = name self.department = department } } ContentView import SwiftUI struct ContentView: View { @State private var selectedDepartment: Department? var body: some View { NavigationSplitView { DepartmentList(selectedDepartment: $selectedDepartment) } detail: { if let department = selectedDepartment { StudentList(department: department) } else { Text("no department selected") } } .task { printStoreFilePath() } } private func printStoreFilePath() { let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask) if let path = urls.map({ $0.path(percentEncoded: false) }).first { print("Storage: \(path)") } } } DepartmentList import SwiftUI import SwiftData struct DepartmentList: View { @Binding var selectedDepartment: Department? @Query(sort: \.name) private var departments: [Department] @Environment(\.modelContext) private var modelContext var body: some View { List(selection: $selectedDepartment) { ForEach(departments) { department in NavigationLink(value: department) { Text(department.name) } } } .toolbar { ToolbarItem { Button { addDepartment() } label: { Label("Add", systemImage: "plus") } } } } private func addDepartment() { guard let index = (1000..<10000).randomElement() else { return } let department = Department(id: UUID(), name: "Department \(index)") modelContext.insert(department) } } StudentList import SwiftUI import SwiftData struct StudentList: View { var department: Department @Query private var students: [Student] @Environment(\.modelContext) private var modelContext init(department: Department) { self.department = department let departmentID = department.id let filter = #Predicate<Student> { student in student.department?.id == departmentID } let query = Query(filter: filter, sort: \.name) _students = query } var body: some View { List { ForEach(students) { student in Text(student.name) } } .toolbar { ToolbarItem { Button { addStudent() } label: { Label("Add", systemImage: "plus") } } } } private func addStudent() { guard let index = (1000..<10000).randomElement() else { return } let student = Student( id: UUID(), name: "Student \(index)", department: department ) modelContext.insert(student) } }
Posted
by
Post not yet marked as solved
1 Replies
710 Views
Hi, does anyone know how to get @Relationship in SwiftData to cascade to the CloudKit container? I've managed to get SwiftData classes to show up in CloudKit but they are not related in line with the @Relationship as per the example project: @Relationship(.cascade) var bucketListItem: [BucketListItem] = []` They are simply separate records. As result the cascade of deletes doesn't work. Any ideas?
Posted
by
Post not yet marked as solved
0 Replies
556 Views
SwiftData provides a mechanism to periodically implicitly save a ModelContext to persistent storage. This is an operation that could fail, as evidenced by the explicit save() method being marked as throws. But what happens if the context attempts to save automatically, and that operation fails? Is there any mechanism for notifying the app? Any way for the app to recognize that it has happened, and to attempt to correct the situation? Presumably, it doesn't just crash (and lose the user's unsaved changes…).
Posted
by
610