Post not yet marked as solved
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.
Post not yet marked as solved
Did anyone successfully used transformable in SwiftData to store UIColor or SwiftUI Color type?
@Attribute(.transformable) var color: UIColor
Post not yet marked as solved
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!
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
Post not yet marked as solved
Problem
The following code doesn't work:
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
Console Error
Query encountered an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.unsupportedPredicate)
Root cause
Size is an enum, #Predicate works with other type such as String however doesn't work with enum
Enum value is saved however is not filtered by #Predicate
Environment
Xcode: 15.0 (15A240d) - App Store
macOS: 14.0 (23A339) - Release Candidate
Steps to reproduce
Run the app on iOS 17 or macOS Sonoma
Press the Add button
Notice that the list remains empty
Expected behaviour
List should show the newly created small car
Actual behaviour
List remains empty inspite of successfully creating the small car.
Feedback
FB13194334
Code
Size
enum Size: String, Codable {
case small
case medium
case large
}
Car
import SwiftData
@Model
class Car {
let id: UUID
let name: String
let size: Size
init(
id: UUID,
name: String,
size: Size
) {
self.id = id
self.name = name
self.size = size
}
}
ContentView
struct ContentView: View {
var body: some View {
NavigationStack {
CarList(size: .small)
}
}
CarList
import SwiftUI
import SwiftData
struct CarList: View {
let size: Size
@Environment(\.modelContext)
private var modelContext
@Query
private var cars: [Car]
init(size: Size) {
self.size = size
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
_cars = Query(filter: predicate, sort: \.name)
}
var body: some View {
List(cars) { car in
VStack(alignment: .leading) {
Text(car.name)
Text("\(car.size.rawValue)")
Text(car.id.uuidString)
.font(.footnote)
}
}
.toolbar {
Button("Add") {
createCar()
}
}
}
private func createCar() {
let name = "aaa"
let car = Car(
id: UUID(),
name: name,
size: size
)
modelContext.insert(car)
}
}
Post not yet marked as solved
I've been testing out SwiftData but haven't bee able to get ModelContext notifications working. I've tried both an objc observer and for await patterns but it never fires. If I listen for the older nsmanagedcontext notifications they are firing, but I am hoping that the new ones give an ID instead of an objectId. Has anyone got these working?
Attempt 1:
class NotificationObserver {
init() {
let didSaveNotification = ModelContext.didSave
NotificationCenter.default.addObserver(self, selector: #selector(didSave(_:)),
name: didSaveNotification, object: nil)
}
@objc func didSave(_ notification: Notification) {
print(notification.name)
}
}
Attempt 2:
class NotificationObserver {
init() {
let didSaveNotification = ModelContext.didSave
Task {
for await note in NotificationCenter.default.notifications(named: didSaveNotification) {
print(note)
}
}
}
}
Post not yet marked as solved
I have a Model Class Note:
@Model
class Note {
var id: UUID
var created: Date
var content: String
@Relationship(inverse: \Event.notes)
var events: [Event]?
init(_ content: String, created: Date = .now, events: [Event] = []) {
self.id = UUID()
self.created = created
self.content = content
self.events = events
}
}
And Event:
@Model
class Event: Hashable, Equatable {
var id: String
var name: String
var eventNotes: String?
@Relationship var notes: [Note]?
// @Transient does not publish (iOS bug?), use .ephemeral instead
@Attribute(.ephemeral) var isSelected: Bool = false
init(_ name: String = "Unnamed Event", calendarId: String, eventNotes: String) {
self.id = calendarId
self.name = name
self.eventNotes = eventNotes
}
init(from calendarEvent: EKEvent) {
self.id = calendarEvent.eventIdentifier
self.name = calendarEvent.title
self.eventNotes = calendarEvent.notes ?? ""
}
...
static func loadEvents(date: Date = Date()) -> [Event] {
...
}
}
I have the following View hierarchy
NoteInputView which has @State var events: [Event] = []
SelectEventButton which has @Binding var events: [Event] and calls Event.loadEvent() to retrieve list of events
SelectEventSheet which has @Binding var events: [Event] and lets the user toggle isSelected
GitHub Gist with all relevant files
Adding notes with same events crashes...
With this setup, I attempt so save new notes in NoteInputView by calling addNote:
func addNote() -> Note {
let selectedEvents = events.filter({ $0.isSelected })
let note = Note(newNoteContent, events: selectedEvents)
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
This works for the first note after opening the app, or if every subsequent note has a different event selected. However, storing a second note with the same event crashes with the following error:
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'events' between objects in different contexts"
(complete error see here) The error occurs at context.insert, which doesn't throw.
If I force quit the app, and then add a note with the same events as an already persisted note, no error is thrown (until a I add another note with the same event without force-quitting).
... but not because one cannot refer to the same events twice
It's not a problem of referring to the same events, as the following code also works fine for multiple notes:
func addNote() -> Note {
// This works, despite notes also always referring to the same events
let note = Note(newNoteContent, events: Event.loadEvents())
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
.
... workaround? Manually adding events to the context before adding it to the notes
One workaround seems to be to add the events to the context before adding the note:
func addNote() -> Note {
let selectedEvents = events.filter({ $0.isSelected })
selectedEvents.forEach({context.insert($0)})
let note = Note(newNoteContent, events: events)
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
.
... but why?
While this works, I cannot quite make sense of this. It seems that passing events around between views may be the culprit, or that loadEvents is called in a child view.
Would love some advice, since this doesn't seem like intended behavior.
Post not yet marked as solved
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
Post not yet marked as solved
When running a macOS app on Xcode 15 Beta 5 (15A5209g), I get a Symbol Not Found error.
Problem: App will not run. Error received. Symbol Not Found: SwiftData Default Backing For AC
Environment: Version 15.0 beta 5 (15A5209g), macOS 14.0 Beta (23A5257q)
App: macOS
SwiftData Model
@Model
class Audit {
init() { }
}
Error:
dyld[875]: Symbol not found: _$s9SwiftData014DefaultBackingB0C3forACyxGxm_tcfC
Referenced from: <75DF3350-4DD5-3AF4-80DA-B17B0EDD26C2> /Users/dking/Library/Developer/Xcode/DerivedData/{redacted}-bigzojxvffztaaaepdczriowvoie/Build/Products/Debug/{redacted}.app/Contents/MacOS/{redacted}
Expected in: /System/Library/Frameworks/SwiftData.framework/Versions/A/SwiftData
Post not yet marked as solved
I have an App Group shared between my app and its widgets.
I have SwiftData's @Model, updated from the widget intent's perform() method and displayed on the app and the widget.
@MainActor
func perform() async throws -> some IntentResult {
let context = try ModelContainer(for: MyModel.self).mainContext
let myModel = try ModelContainer(for: MyModel.self).mainContext.fetch(
FetchDescriptor<MyModel>(predicate: #Predicate {
// The predicate is not the problem.
})
).first
myModel?.functionThatModifiesMyModel()
return .result()
}
Both the app and the widget SwiftUI views access to the model using Macros.
@Environment(\.modelContext) var context
@Query(sort: \.whatever) var myModel: [MyModel]
But the data is never correct in the app code (the widget's data is updated correctly using the intent).
Why doesn't the model make it to the app?
Post not yet marked as solved
PersistentModel is a protocol but would make more sense as a class that we then subclass. If all of the implementation was in a parent class of our model classes then there wouldn't be all the problems caused by requiring the use of the @Model macro, e.g. default property values not working, unable to subclass, overriding get/set not possible, conflict in property names...
Post not yet marked as solved
The Sendable documentation says we can mark reference types as Sendable if they "internally manage access to their state."
Adding Sendable conformance to my SwiftData classes silences warnings such as the following: "Non-sendable type '[Item]' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary"
@Model final class Item: Sendable {
var sampleProperty = ""
}
My understanding is that the compiler would complain if adding explicit Sendable conformance to a swift data model was breaking concurrency rules, but I wanted to check with the community to see what everyone thinks.
Best,
Taylor
Post not yet marked as solved
Does SwiftData support UIImage as in CoreData specified here: https://www.swiftdevjournal.com/saving-images-in-core-data/ If it does, how to specify that in the @Model schema, especially using external storage to save the image in a separate file. Thanks.
Post not yet marked as solved
I'm trying to instantiate my model and I'm getting an error on the set first property
import Foundation
import SwiftData
@Model final class PointModel {
var x: CGFloat
var y: CGFloat
init(
x: CGFloat,
y: CGFloat
) {
self.x = x
self.y = y
}
}
extension PointModel {
static var preview: PointModel {
PointModel(x: 0, y: 0)
}
}
let point = PointModel(x: location.x, y: location.y)
{
get {
_$observationRegistrar.access(self, keyPath: \.x)
return self.getValue(for: \.x)
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.x) {
self.setValue(for: \.x, to: newValue) **Thread 1: Fatal error: Illegal attempt to use a nil as an Attribute - x + 151.0**
}
}
}
Has anyone else experienced this problem?
Maybe someone knows how to solve this?
re: the SwiftData session "Create an app with SwifData" (https://developer.apple.com/videos/play/wwdc2023/10154)
I corrected the @MainActor issue, but it seems to only work with the main ContentView and not other views.
I get the following error for TripListItem for example :
failed to find a currently active container for Trip
Post not yet marked as solved
Hi all,
I am trying to render my SwiftUI views that uses SwiftData classes using sample data using the approach shown in the example code of wwdc2023-10196:
@MainActor #Preview {
TripsWidgetEntryView()
.modelContainer(PreviewSampleData.container)
}
Unfortunately this seems no longer valid.
Indeed I get this error:
I then tried to remove the @MainActor as suggested, but the error in then moved to another level:
What do you suggest to be the best approach to have back my preview working?
I am using Xcode Beta 4 - 15A5195m
Post not yet marked as solved
Hello,
I have just tried playing around with the new Swift Data framework and noticed something.
Assume the following many-to-many relationship on two PersistentModels:
@Model
class Media {
@Relationship(.nullify, inverse: \Tag.medias)
var tags: [Tag]
}
@Model
class Tag {
var medias: [Media]
}
This compiles without problems. If we now make Media conform to Codable (or just Decodable), we get a compiler error: "Ambiguous use of 'getValue(for:)'".
When expanding the @Model and the then revealed @PersistedProperty macro, we see that the error is in the getter of Tag.medias, where we call self.getValue(for: \.medias). It seems the compiler knows multiple overloads of this function, including:
an overload that accepts a KeyPath with a PersistentModel value
an overload that accepts a KeyPath with a Decodable value
Since Media conforms to both protocols, the compiler understandably does not know which overload to use.
So to my questions:
Is this intended behavior? So are PersistentModels not supposed to be Decodable?
If yes, what would be the preferred way (or a clean way) to decode a PersistentModel (e.g., from an API)?
Best regards,
Jonas
Post not yet marked as solved
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.)
Post not yet marked as solved
Using SwiftData, I have a model that uses an enum as a property and a custom Codable type
import SwiftData
import CoreLocation
// MARK: - Main Model
@Model
class Cache {
var size: CacheSize?
var coordinates: CLLocationCoordinate2D
}
// MARK: - CacheSize Enum
enum CacheSize: CaseIterable, Codable {
case nano
case micro
case small
case regular
case large
case veryLarge
case notChosen
case virtual
case other
}
// MARK: - Codable for CLLocationCoordinate2D
extension CLLocationCoordinate2D: Codable {
enum CodingKeys: String, CodingKey {
case lat, lng
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.latitude, forKey: .lat)
try container.encode(self.longitude, forKey: .lng)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let latitude = try container.decode(CLLocationDegrees.self, forKey: .lat)
let longitude = try container.decode(CLLocationDegrees.self, forKey: .lng)
self.init(latitude: latitude, longitude: longitude)
}
}
When I fetch the object from the ModelContext and try to access the property corresponding to this enum, I have a fatal error raised in BackingData.swift:
SwiftData/BackingData.swift:197: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(iGeo.CacheSize, Swift.DecodingError.Context(codingPath: [], debugDescription: "Invalid number of keys found, expected one.", underlyingError: nil))
When I try to read the CLLocationCoordinates2D property, I have also a crash in the Decodable init(from decoder: Decoder implementation when trying to read the first value from the container.
Did I miss something here or did something wrong?
When trying to delete the element from my list, I always got error in my model.
get {
_$observationRegistrar.access(self, keyPath: \.id)
return self.getValue(for: \.id) <-- ERROR: Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1a949aefc)
}
Because I am new in development, I don't know how to solve it.