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.

Posts under SwiftData tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

SwiftData #Predicate cannot test for nil relationship
In Xcode Version 15.0 beta (15A5160n) this predicate will not build: let thisPredicate = #Predicate<Ledgers> { ($0.myStore != nil) } The definition of .myStore in the Ledgers class is: var myStore: Stores? an optional relationship. Is there anyway to test for nil optional relationships in SwiftData? The inverse relationship in Stores is: @Relationship(.deny, inverse: \Ledgers.myStore) var myReceipts: [Ledgers]
10
2
1.9k
Oct ’23
SwiftData model in Swift package
Hi, I am looking for information on how to setup a ModelContainer for a Swift app when the SwiftData model is located in a Swift package. Let's say the model code resides in a package called DomainModel. That package was added target's embedded content and the model types are used to init the model container using the modelContainer(for:) view modifier on the ContentView of the app. This crashes the app on startup with a EXC_BAD_ACCESS code=2. When copying the model code from the package directly into the app, the app starts just fine. I kindly ask for a code sample or any information about how to setup the model container when using a model from a Swift package. Thanks in advance and I am looking forward to replacing CoreData πŸ™‚
6
0
1.7k
Aug ’23
Do I need to add my own unique id?
Hi, if I have a @Model class there's always an id: PersistentIdentifier.ID underneath which, according to the current documentation "The value that uniquely identifies the associated model within the containing store.". So I am wondering if it is (good) enough to rely on this attribute to uniquely identify @Model class entities, or if there are edge cases where it does not work (like maybe when using CloudKit)? If anybody saw some information regarding this, please let me know :-) Cheers, Michael
4
3
1.4k
Aug ’23
Access Core Data ModelContainer with SwiftData
I have an app that uses CoreData and I want to migrate to SwiftData. After following the Migrate to SwiftData session, I only need to point to my old Core Data file to read the old data and convert it to the new SwiftData format. My question is how do I do this? Maybe worth mentioning is that my NSPersistentContainer(name: "Model") is different to my app name. Possible Solution? According to a Tweet by Donny Wals this is done this way: By default a SwiftData ModelContainer will create its underlying storage in a file called default.store. If you want to change this so you can use an existing Core Data SQLite file, you can point your container to that file instead: // point to your old sqlite file let url = URL.applicationSupportDirectory.appending(path: "Model.sqlite") let config = ModelConfiguration(url: url) modelContainer = try ModelContainer(for: [ Movie.self ], config) My Tested Code @main struct SwiftData_TestApp: App { let url = URL.applicationSupportDirectory.appending(path: "Model.sqlite") let config = ModelConfiguration(url: url) let modelContainer = try ModelContainer(for: [ Item.self ], config) var body: some Scene { WindowGroup { ContentView() } .modelContainer(modelContainer) } } The problem here is that I don’t get it to work in the main app struct. When using this the way described in Dive deeper into SwiftData (at 6:58) I only get the error: Cannot use instance member 'url' within property initializer; property initializers run before 'self' is available PS: There seems to be an issue with this WWDC session method anyway – see this post.
2
0
2.0k
May ’24
@Model issue in visionOS
It seems that @Model is not fully supported in visionOS. I've tried both an iPad app and a native visionOS app, and both crash when trying to use SwiftData. It's a minimal app from the template (no data) that I add a little data code to: import SwiftData @Model final class mapPin { var lat : Double var lon : Double init(lat: Double, lon: Double) { self.lat = lat self.lon = lon } } Building for visionOS produces: /var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMm_.swift:2:13: error: declaration name '_$backingData' is not covered by macro 'Model' private var _$backingData: any SwiftData.BackingData<mapPin> = SwiftData.DefaultBackingData(for: mapPin.self) ^ /Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here final class mapPin { ^~~~~~~~~~~~~~ /var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMc_.swift:1:1: error: type 'mapPin' does not conform to protocol 'PersistentModel' extension mapPin : SwiftData.PersistentModel {} ^ /Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here final class mapPin { ^~~~~~~~~~~~~~ /var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMc_.swift:1:1: note: do you want to add protocol stubs? extension mapPin : SwiftData.PersistentModel {} ^ /Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here final class mapPin { ^~~~~~~~~~~~~~ /var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMm_.swift:2:64: error: module 'SwiftData' has no member named 'DefaultBackingData' private var _$backingData: any SwiftData.BackingData<mapPin> = SwiftData.DefaultBackingData(for: mapPin.self) ^~~~~~~~~ ~~~~~~~~~~~~~~~~~~ /Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here final class mapPin { ^~~~~~~~~~~~~~```
8
2
1.5k
Aug ’23
Inserting a Model entity with a relationship results in a runtime error.
Hi, when inserting an entity with a relationship I get the following runtime error: Illegal attempt to establish a relationship 'group' between objects in different contexts [...]. The model looks like this: @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } It can be reproduced using this (contrived) bit of code: let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() (See also full test case below). Anybody experiencing similar issues? Bug or feature? Cheers, Michael Full test case: import SwiftData import SwiftUI import XCTest // MARK: - Person - @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } // MARK: - Group - @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } // MARK: - SD_PrototypingTests - final class SD_PrototypingTests: XCTestCase { var container: ModelContainer! var ctx: ModelContext! override func setUpWithError() throws { let fullSchema = Schema([Person.self, Group.self,]) let dbCfg = ModelConfiguration(schema: fullSchema) container = try ModelContainer(for: fullSchema, dbCfg) ctx = ModelContext(container) _ = try ctx.delete(model: Group.self) _ = try ctx.delete(model: Person.self) } override func tearDownWithError() throws { guard let dbURL = container.configurations.first?.url else { XCTFail("Could not find db URL") return } do { try FileManager.default.removeItem(at: dbURL) } catch { XCTFail("Could not delete db: \(error)") } } func testRelAssignemnt_FB12363892() throws { let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() } }
4
3
2.0k
Aug ’23
EXC_BAD_ACCESS when initializing a Model class with a custom class property
I have multiple classes that are contained within one another. Initializing class A(no other classes as properties) has no issues, but the moment that it tries to initialize class B, which takes class A as a property, an EXC_BAD_ACCESS error is thrown while attempting to set the first property value. Class A: import Foundation import SwiftData @Model public class Service: Identifiable, Equatable, Codable { @Attribute(.unique) public var id: UUID public var title: String public var price: Int public var stripePriceId: String public var servicePhoto: String public var serviceLength: Int public var category: [String] init(id: UUID, title: String, price: Int, stripePriceId: String, servicePhoto: String, serviceLength: Int, category: Array<String>) { self.id = id self.title = title self.price = price self.stripePriceId = stripePriceId self.servicePhoto = servicePhoto self.serviceLength = serviceLength self.category = category } } Class B: import Foundation import SwiftData import SwiftUI @Model public class ServiceOrder: Identifiable, Codable, Equatable { public var id: UUID @Relationship(.noAction) public var service: Service public var quantity: Int = 1 public var subtotal: Int { return service.price * quantity } public init(id: UUID = UUID(), service: Service, quantity: Int) { self.id = id self.service = service self.quantity = quantity } public func getValue<T>(for key: KeyPath<ServiceOrder, T>) -> T { return self[keyPath: key] } // This is where the error is being thrown. The custom setValue and getValue methods were added to every class to mitigate an 'Ambiguous use of __Value()' error, but that's for another thread public func setValue<T>(for key: ReferenceWritableKeyPath<ServiceOrder, T>, to newValue: T) { self[keyPath: key] = newValue } // This was added to see if following the Builder pattern might mitigate the issue by ensuring that all properties were initialized before being passed in, it did not change anything class ServiceOrderBuilder { private var id: UUID? private var service: Service? private var quantity: Int? init() { } init(id: UUID = UUID(), service: Service, quantity: Int = 1) { self.id = id self.service = service self.quantity = quantity } func setId(id: UUID = UUID()) -> ServiceOrderBuilder { self.id = id return self } func setService(service: Service) -> ServiceOrderBuilder { self.service = service return self } func setQuantity(quantity: Int = 1) -> ServiceOrderBuilder { self.quantity = quantity return self } func build() -> ServiceOrder? { guard let id = id, let service = service, let quantity = quantity else { return nil } return ServiceOrder(id: id, service: service, quantity: quantity) } } Here's where I'm doing the initialization of everything. I'm trying to just create sample data. import SwiftData import Foundation @MainActor public let previewContainer: ModelContainer = { do { var container = try ModelContainer( for: [Event.self, Braider.self, Queue.self, QueueSlot.self, Cart.self, ServiceOrder.self], ModelConfiguration(inMemory: true) ) var context = container.mainContext var serviceSampleData: [Service] = [ Service( id: UUID(), title: "Event Braid", price: 20, stripePriceId: "", servicePhoto: "", serviceLength: 15, category: []), ..., ] serviceSampleData.forEach { service in context.insert(service) } // This is where the error is thrown, no issue initializing the above Services var serviceOrder1: ServiceOrder = ServiceOrder( service: serviceSampleData[0], quantity: 1) context.insert(serviceOrder1) // ...continue building higher classes/Models that utilize the lower ones return container } catch { print("Failed to create container") do { return try ModelContainer( for: [Event.self], ModelConfiguration(inMemory: true) ) } catch { fatalError() }} }() I assumed that this was a SwiftData issue, as I mentioned in response to this post but looking back this issue has been happening for 7+ years, so now I'm assuming I'm doing something incorrect.
1
0
974
Aug ’23
How to make SwiftData class Codable
Consider the Categories class below. Without the @Model line, Xcode has no problems. As soon as the @Model line is added, Xcode protests that the class does not conform to Decodable or Encodable. Apparently the @Model macro expanded macro prevents the implied boilerplate that the systems adds when the Codable protocol is added to the class. I've filed feedback (FB12444837) for this. Does anyone have suggestions that will let me avoid the boilerplate? This is the simplest class in my schema, I've got 12 other classes with many more variables. @Model class Categories: Identifiable, Codable { // MARK: Identifiable var id: UUID { return uuidKey } // MARK: - Properties @Attribute(.unique) var uuidKey: UUID = UUID() var dateCreated: Date = Date() var dateModified: Date = Date() var dateRealm: Date? = nil var uuidUser: UUID = UUID() var uuidFamily: UUID = UUID() var myName: String = "" }
5
7
2.2k
Sep ’23
How to form a search predicate using swift data with a one to many model
I am working in Xcode 15 (beta) migrating to SwiftData and am having a hard time figuring out how to form a search predicate for my one to many model. The desired result is to return a query that returns only the articles and sections where the article "search" field contains the string a user is searching for. Here is my current model: @Model class SectionsSD { @Attribute(.unique) var id: String var section: String var rank: String var toArticles: [ArticlesSD]? init(id:String, section: String, rank: String) { self.id = id self.section = section self.rank = rank } } @Model class ArticlesSD { var id: String var title: String var summary: String var search: String var section: String var body: String @Relationship(inverse: \SectionsSD.toArticles) var toSection: SectionsSD? init(id: String, title: String, summary: String, search: String, section: String, body: String) { self.id = id self.title = title self.summary = summary self.search = search self.section = section self.body = body } } In CoreData I was able to do the following in my code to form and pass the search predicate ("filter" being the user input search text, "SectionsEntity" being my old CoreData model): _fetchRequest = FetchRequest<SectionsEntity>(sortDescriptors: [SortDescriptor(\.rank)], predicate: NSPredicate(format: "toArticles.search CONTAINS %@", filter)) I can't find any examples or info anywhere that explains how to form a predicate in SwiftData to achieve the same search results. I can't seem to find a way to represent toArticles.search properly assuming the capability is there. Here is what I've tried but Xcode complains about the $0.toArticles?.contains(filter) with errors about "Cannot convert value of type 'Bool?' to closure result type 'Bool'" and "Instance method 'contains' requires the types 'ArticlesSD' and 'String.Element' (aka 'Character') be equivalent" let searchPredicate = #Predicate<SectionsSD> { $0.toArticles?.contains(filter) } _sectionsSD = Query(filter: searchPredicate) I've tried $0.toArticles?.search.contains(filter) but Xcode can't seem to find its way there like it did using CoreData Any suggestions and examples on how to form a predicate in this use case would be appreciated.
7
1
4.7k
Aug ’23
SwiftData nested custom model CRASH
@Model class AModel { @Attribute(.unique) var id:String var date:Date var b:[BModel] init() { self.id = UUID().uuidString self.date = Date() self.b = [] } } @Model class BModel { @Attribute(.unique) var id:String var date:Date init() { self.id = UUID().uuidString self.date = Date() } } struct MainView: View { @Environment(\.modelContext) private var db @State private var a:AModel = AModel() var body: some View { VStack { } .onAppear { a.b.append(BModel()) print(a.b) } } } // CRASH : @Model class AModel { @Attribute(.unique) var id:String var date:Date var b:[BModel] /** Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) { get { _$observationRegistrar.access(self, keyPath: \.b) return self.getValue(for: \.b) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.b) { self.setValue(for: \.b, to: newValue) } } } */ init() { self.id = UUID().uuidString self.date = Date() self.b = [] } } @Model class BModel { @Attribute(.unique) var id:String var date:Date init() { self.id = UUID().uuidString self.date = Date() } }
3
4
1.5k
Aug ’23
Thread 1: Fatal error: expected attribute to be Codable
Not sure what I'm doing wrong here. I'm taking this opportunity to add persistence to an app that hadn't had it yet. I followed the session advice but I get this crash when running it: SwiftData/BackingData.swift:201: Fatal error: expected attribute to be Codable The crash is on this line: modelContext.insert(RentSplitDataModel()) The object being created and inserted there is simple and the compiler confirms it does conform to Codable: https://github.com/KyLeggiero/Rent-Split-for-iOS/blob/feature/MVP/Shared/Model/RentSplitDataModel.swift
7
1
1.6k
Sep ’23
SwiftData error 134020 - "The model configuration used to open the store is incompatible with the one that was used to create the store."
Hi all, I have tried everything (that i'm aware of) but i cannot seem to get around this error. My app is setup using only SwiftData and is basically a custom version of the apps shown in SwiftData docs. I have done the following to try to debug: Deleted app from device Clean and re-build Delete derived data and rebuild I have tried reverting changes made to the @Models i have define Every combination of the above steps + rebuilding Im at a loss. No clue how to resolve this. Some weird observations. This error only occurs after the first context.insert call. The first is successful and data is properly persisted across app launches. All subsequent attempts to insert result in the following error: Error Domain=NSCocoaErrorDomain Code=134020 "The model configuration used to open the store is incompatible with the one that was used to create the store." UserInfo={NSAffectedObjectsErrorKey=<NSManagedObject: 0x2824004b0> (entity: Track; id: 0x2807a7de0 <x-coredata:///Track/tB9B77486-8F60-4F63-848D-D1C5CC67BA526>; data: { createdAt = "2023-07-02 23:45:45 +0000"; name = Test; })}
5
3
1.6k
Sep ’23
CloudKit failed due to SwiftData used in both WatchOS and WidgetExtension
I have a WidgetExtension using SwiftData (same ModelContainer setup used in the WatchApp: @main struct Watch_Widget: Widget { let kind: String = "Watch_Widget" var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider()) { entry in Watch_WidgetEntryView(entry: entry) .modelContainer(for: [Model1.self, Model2.self]) } .configurationDisplayName("App") .description("descriptions") } } Here's the same model used in the widget view: struct Watch_WidgetEntryView : View { @Query var models: [Model1] var body: some View { let gaugeVal = models.count Gauge(value: gaugeVal, in: 0...60) { Text("min") } currentValueLabel: { Text(String(Int(gaugeVal))) } .gaugeStyle(.accessoryCircular) .widgetLabel { Text("\(models.count) models") } .containerBackground(.fill.tertiary, for: .widget) } } When I build the WidgetExtension, the following error was thrown and the CK data isn't loaded properly: CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process.
2
0
973
Jan ’24
Trouble with Persisting One-to-Many Relationship Data in SwiftData, What am I Missing?
Hi everyone, I'm new to programming and I've been experimenting with Apple's SwiftData. I've run into an issue I can't seem to resolve. I'm creating a personal relationship manager app where I have a Relation model and an Interaction model. Relation has a one-to-many relationship with Interaction. I'm using SwiftData's @Model and @Relationship property wrappers to define these models and their relationship. I've taken inspiration from Apple's sample code, that can be found here: Adopting SwiftData for a Core Data app (WWDC23 Session: "Migrate to SwiftData") The relevant parts of the models look something like this: @Model final class Relation { ... @Relationship(.cascade, inverse: \Interaction.relation) var interactions: [Interaction] = [] ... } @Model final class Interaction { ... var relation: Relation? ... } In my SwiftUI view, I'm adding a new Interaction to a Relation like this: private func AddItem() { withAnimation { let newInteraction = Interaction(...) modelContext.insert(newInteraction) newInteraction.relation = relation relation.interactions.append(newInteraction) } } When I add a new Interaction like this, everything seems to work fine during that app session. I can see the new Interaction in my app's UI. But when I quit the app and relaunch it, the new Interaction is gone. It's as if it was never saved. I've double-checked my code and as far as I can tell, I'm using SwiftData correctly. My usage aligns with the sample code provided by Apple, and I'm not getting any errors or warnings. I think that this issue is not related to SwiftData being in Beta, because Apple's sample code works perfectly fine. I have a few questions: Is there something I'm missing about how to properly save models using SwiftData? Is there a specific step or method I need to call to persist the changes to the Relation and Interaction objects? Is there a way to debug what's going wrong when SwiftData attempts to save these changes? Any help would be greatly appreciated. Thank you in advance! Louis
2
0
1.7k
Aug ’23
NSUnknownKeyException: not key value coding-compliant for the key "(null)"
In Xcode 15 beta 3 and iOS 17 beta 3, my app with SwiftData keeps generating error: *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSManagedObject 0x2811cb390> setValue:forUndefinedKey:]: the entity dataSets is not key value coding-compliant for the key "(null)".' I have a model: @Model final class Station: Sendable { ... var dataSets: [String] } The error seems to occur when saving entities of the model in SwiftData. There is no entity named "dataSets". Only a property in the above model. What's the null key in the error?
3
3
1.2k
Aug ’23
How to wire SwiftData up to external data sources?
In one of the WWDC 2023 videos a presenter said in passing that you can connect SwiftData to whatever complicated setup you have. I haven't been able to find any documentation or connection points for this though. Obviously I can fetch the data myself and call context.insert(...) for every item, but what about refreshes, deletes, inserts, updates? Where can I wire up these external calls and their responses? Thanks!
1
1
809
Oct ’23