Is SwiftData going to be immediately available to use with iOS 16? I ask because I'm working on an app which I'd like to release around the end of this month, and I'm about to implement CoreData for it, but wanted to see when SwiftData would be available. My guess was that SwiftData is for iOS 17 so I should just stick with CoreData for now and switch over later, but just wanted to check to make sure. Thanks!
SwiftData
RSS for tagSwiftData 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
I did manage to save my Entities to CloudKit with SwiftData but the default database is the private database. I need to store some Entities in the private and other Entities in the public CloudKit database. How do I manage that with SwiftData? With CoreData I always used different configurations for both private and public and added the entities to one or the other.
Hi,
re: the SwiftData session "Create an app with SwifData" (https://developer.apple.com/videos/play/wwdc2023/10154)
I noted the mention of generating sample preview data. In CoreData, I had a similar need and this was achieved by creating a shared in-memory context; fairly straight forward.
The example given for SwiftData was decorated with @MainActor and then added to the target project, then in the #Preview closure, the modelContainer is amended to point to the preview data. Anyways, my problem is that I'm receiving an error when trying to render the preview in question:
main actor-isolated let 'previewContainer' can not be referenced from a non-isolated context
I suppose my issue is not having used the MainActor wrapper before and being unclear on what's possibly going wrong here (or if it's not just a "me" problem).
Can anyone help?
How does SwiftData work with background operations? CoreData had background context that could be used to avoid UI hang for heavy operations.
Is there an equivalent in SwiftData, and if so, do I have to merge changes or does it save directly to persistent store?
Using the 'Create SwiftData Code...' action in Xcode results in Model that have bi-directional relationships between many of my entities (which is correct - my Core Data model includes this).
All of these Relationships are marked as invalid, however, with the following error:
Circular reference resolving attached macro 'Relationship'
Most ORM's, in my experience, have a way to mark one end of a bidirectional relationship as an 'owner'. Is there something similar available in SwiftData, or is this scenario handled in a different way? Or am I going to need to remove all of my bidirectional relationships?
It seems that when you delete model objects with a relationship there seems to be a crash occurring if the collection your observing is tied to a ForEach. Below is an example of the models in SwiftData
@Model
class Category {
@Attribute(.unique)
var title: String
var items: [Item]?
init(title: String = "") {
self.title = title
}
}
The relationship is defined between the category and the item
@Model
final class Item {
var title: String
var timestamp: Date
var isCritical: Bool
var isCompleted: Bool
@Relationship(.nullify, inverse: \Category.items)
var category: Category?
init(title: String = "",
timestamp: Date = .now,
isCritical: Bool = false,
isCompleted: Bool = false) {
self.title = title
self.timestamp = timestamp
self.isCritical = isCritical
self.isCompleted = isCompleted
}
}
So if I were to create a category individually so i can later tag it to an item i'm just following the standard proceedure of creating a category and inserting it into the context as you can see below
Button("Add Category") {
let category = Category(title: title)
modelContext.insert(category)
}
.disabled(title.isEmpty)
Then later on when i create my item I associated an existing category with an item and insert that into the context so now there is a possibility to have many items associated to a single category as you can see below
@State var item = Item()
// Item is bound to form elements
....
Button("Create") {
modelContext.insert(item)
item.category = selectedCategory.title == "None" ? nil : selectedCategory
dismiss()
}
This is where the problem occurs...
If i try to delete a category now after inserting it
@Query private var categories: [Category]
....
ForEach(categories) { category in
Text(category.title)
.swipeActions(allowsFullSwipe: true) {
Button(role: .destructive) {
withAnimation {
modelContext.delete(category)
}
} label: {
Label("Delete", systemImage: "trash.fill")
}
}
}
The application crashes because the foreach is still being executed by the Query property wrapper as if the item still exists even though it has been deleted, but it's trying to access the title on an object that doesn't exist anymore.
I've also noticed that when trying to insert duplicate items using the Atrribute macros this causes a crash too.
It's almost as if the query collection just isn't being updated with the new values of a category being deleted. I've filed a feedback under FB12286699 (Crash when deleting items in relationships) in Feedback assistent hopefully this can get picked up.
If I make model changes in the mainContext using a batch operation like context.update OR on a background thread ModelContext ModelContext(container), my saved changes are not automatically reflected in the UI (a List of models).
Also ModelContext.willSave and ModelContext.didSave don't seem to get called.
Will automatic UI updates work in an upcoming Beta but are NOT in Beta 1?
Or will we refresh View/@Query based on a ModelContext.didSavenotification?
Or should this be working in Beta 1 and I am missing how it works?
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.+++")
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
Did anyone successfully used transformable in SwiftData to store UIColor or SwiftUI Color type?
@Attribute(.transformable) var color: UIColor
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
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.
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
}
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)")
}
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?
Hi, I want to subclass my model.
Here is my superclass:
import SwiftData
@Model
public class Control {
@Attribute(.unique)
public var frame: Frame
init(frame: Frame) {
self.frame = frame
}
}
Here is my subclass:
import SwiftData
import CoreGraphics
class SliderControl: Control {
let axis: Axis
var value: CGFloat = 0.0
init(axis: Axis, frame: Frame) {
self.axis = axis
super.init(frame: frame)
}
required public init(backingData: any BackingData<Control>, fromFetch: Bool = false) {
// How to get `axis` and `value` from the backing data?
}
}
I'm not sure how to use the backing data to re-create my object.
My goal is to have multiple controls with unique properties.
I test with a simple class and it can compile:
@Model
final class Book: Encodable {
var name: String
enum CodingKeys: CodingKey {
case name
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
}
}
Then I try with the Trip class from sample and it cause an error:
@Model final class Trip: Encodable {
:
enum CodingKeys: CodingKey {
case name, destination, endDate, startDate, bucketList
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(destination, forKey: .destination)
try container.encode(endDate, forKey: .endDate)
try container.encode(startDate, forKey: .startDate)
try container.encode(bucketList as! Set<BucketListItem>, forKey: .bucketList)
}
And I got the error Ambiguous use of 'setValue(for:to:)'
I tried make BucketListItem and LivingAccommodation Encodable and still have error.
I haven’t found any way to have a swift data model contain an enum with different associated values, each different types of
models, in order to deal with models that require heterogenous collections. Is this simply not supported? Is it supported but not ever used with SwiftUI binding? Instead I’ve had to create my own sort of enum in the form of a model that contains optionals for every case but this is obviously not ideal.
I'm trying out SwiftData and converting my existing data models using Structs and Codable to Classes and SwiftData. I've got a model that has a Measurement<UnitMass> type. When I run the app after converting everything to use classes with the @Model macro, I get a fatal error: SwiftData/SchemaProperty.swift:325: Fatal error: Unexpected type for CompositeAttribute: NSUnitMass.
Since Measurement conforms to Codable, and SwiftData should work with Codable types, why is this not working?
I also tried marking the property with @Attribute(.transformable) and it didn't make a difference.
Running my app with SwiftData in iOS 17 beta on iPhone leads to error:
cannot open file at line 46973 of [554764a6e7]
os_unix.c:46973: (2) open(/private/var/mobile/Containers/Data/Application/ED4308D5-058B-41BC-A617-A46F9754E3EC/Library/Application Support/default.store) - No such file or directory
API call with unopened database connection pointer
misuse at line 179760 of [554764a6e7]
It seems the database file has not been created yet, since it's the first time running the app with SwiftData.