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
Hi,
I could probably wait until tomorrow's deep dive session and just find out, but I'm curious to ask, are the SwiftData persistent containers still backed on SQLite primarily?
I'm excited to replace Core Data in my existing SwiftUI app, but I've been dropping down to SQLite3 directly, for example, for using the FTS5 module for creating full-text-search tables alongside my Core Data tables to back more relevant results for .searchable UIs.
Post not yet marked as solved
What is the best way to use swift data to store one off data models? For example an application state that you want to be persisted across application launches.
The only examples I've seen use arrays of items which wouldn't work for having just one application state.
Is it possible to query just one item?
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!
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)
}
}
}
}
I just saw the available video according SwiftData and wanted to convert a project of mine.
Both documentation and video mention this:
By default, SwiftData includes all noncomputed properties of a class as long as they use compatible types. The framework supports primitive types such as Bool, Int, and String, as well as complex value types such as structures, enumerations, and other value types that conform to the Codable protocol.
I tried to model an enum but I always get an error regarding the conformance to PersistentModel
I made different type of enum all implementing RawRepresentable but I always get an error
For example:
enum Simple: Int16 {
case one, two
}
@Model
class Item {
var simple: Simple = .one
}
I got those errors:
No exact matches in call to instance method 'getValue'
Candidate requires that 'Simple' conform to 'PersistentModel' (requirement specified as 'Value' : 'PersistentModel')
Candidate requires that 'Simple' conform to 'Sequence' (requirement specified as 'Value' : 'Sequence')
Did I miss something here?
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
Did anyone successfully used transformable in SwiftData to store UIColor or SwiftUI Color type?
@Attribute(.transformable) var color: UIColor
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
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
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.
Post not yet marked as solved
I was wondering if ModelContext's fetch() contains an auto-updating results array? I ask because there is no documentation yet and in the WWDC23 lounge it was suggested by Debbie G to use fetch() to overcome the limitations of @Query i.e. no way to use dynamic filtering or sorting. I suppose we would call fetch() from onAppear and onChanged to support dynamic queries that also have auto-updating of results. Personally I don't understand why @Query and the old @FetchRequest were implemented as property wrappers instead of SwiftUI modifiers, e.g. .fetch(predicate:sort:) to match other modifiers like .task(id:).
I was hoping for it to behave similar to Date's formatted() that returns a locale-aware string that automatically invalidates SwiftUI Text when the locale changes. Although I'm not exactly sure how it works.
If fetch() doesn't auto-update then what would be the point of using it instead of just using NSFetchRequest with dictionary result type to get data into a SwiftUI view struct fast and memory efficient.
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?
Post not yet marked as solved
How secure storing the data using SwiftData? What encryption mechanism is it used to store data? Our project has a requirement to shore data using AES 256 encryption.
Post not yet marked as solved
I'm stuck at an error EXC_BREAKPOINT (code=1, subcode=0x1a8d69a38)that is thrown in a class during initialization.
The class is defined as:
@Model
public final class Parent {
@Attribute(.unique)
public var uuid: UUID
/// The date specification.
@Relationship(.cascade)
public var dateSpec: DateSpec
/// The title.
public var title: Title
/// The subtitle.
public var subTitle: Subtitle
public init(uuid: UUID,
dateSpec: DateSpec,
title: Title,
subTitle: Subtitle) {
self.uuid = uuid
self.dateSpec = dateSpec
self.title = title
self.subTitle = subTitle
}
}
The error is thrown in the var dateSpec property at the return self.getValue(for: \.dateSpec) call of the @PersistedProperty macro.
DateSpec is defined this way:
@Model
public final class DateSpec {
@Attribute(.unique)
public var uuid: UUID
/// The type of the date specification (`.point` or `.range`).
public var type: DateSpecType
@Relationship(.cascade)
public var point: DatePoint
@Relationship(.cascade)
public var range: DateRange
public init(uuid: UUID,
type: DateSpecType = .none,
point: DatePoint = .init(),
range: DateRange = .init()) {
self.uuid = uuid
self.type = type
self.point = point
self.range = range
}
}
And DatePoint is defined so:
@Model
public final class DatePoint {
@Attribute(.unique)
public var uuid: UUID
public var format: String
public var date: Date?
public init(uuid: UUID,
format: String,
date: Date? = nil) {
self.uuid = uuid
self.format = format
self.date = date
}
}
(DateRange accordingly).
So, as far as I understood the sessions, this should work. Or did I miss something?
-- Edit:
When taking out DatePoint and DateRange from the model, and replacing the properties by .transient wrappers that get/set the respective properties directly in DateSpec, then the error disappears.
So, is the problem the cascading of the relationships between Parent and DateSpec, and DateSpec and DatePoint/DateRange?
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?
Post not yet marked as solved
Hello everyone!
I'm trying to run this project by Apple, but it doesn't let me, I'm trying to learn more about to swiftData...
https://developer.apple.com/documentation/coredata/adopting_swiftdata_for_a_core_data_app
On the code it says next:
`@MainActor #Preview {
AddBucketListItemView(trip: .preview)
.modelContainer(PreviewSampleData.container)
}
But it show me next error,
Type 'Trip' has no member 'preview'
anybody knows how can I solved, thank you.
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.
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
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.