Post not yet marked as solved
In CoreData, many-relationships are implemented as NSSet objects. In the SwiftData examples, they are shown as arrays. Are they really arrays (i.e., order-preserving and duplicates allowed) or are they arrays made from CoreData NSSets? In my applications, this makes a HUGE difference.
Post not yet marked as solved
Anyone know the SwiftData equivalet of the CoreData lifecycle methods. and how do we override them or do something similar? eg:
awakeFromInsert()
willSave()
didSave()
willTurnIntoFault()
prepareForDeletion()
Post not yet marked as solved
Hi,
say in my model I have members and each member optionally can have a relationship to a Club. So the relationship in the Member entity would be modelled like so:
@Relationship(.nullify, inverse: \Club.members) var club: Club?
Now I would like to fetch al Members with no Club relationship. I would assume that this would work with a predicate like this:
let noClubPred = #Predicate<Member> { member in
member.club == nil
}
Unfortunately this gives me the following error when compiling:
Generic parameter 'RHS' could not be inferred.
Has anybody an idea how to phrase this predicate correctly, or is this a beta issue and it should actually work?
Thank you!
Cheers, Michael
Post not yet marked as solved
I am trying to run a lightweight migration in which I am changing the name of a model property from name to title. The database is already populated with few records. Those records must be preserved.
Here is my schema versions:
enum TripsSchemaV1: VersionedSchema {
static var versionIdentifier: String? = "Initial version"
static var models: [any PersistentModel.Type] {
[Trip.self]
}
@Model
class Trip {
var name: String
init(name: String) {
self.name = name
}
}
}
enum TripsSchemaV2: VersionedSchema {
static var versionIdentifier: String? = "name changed to title"
static var models: [any PersistentModel.Type] {
[Trip.self]
}
@Model
class Trip {
@Attribute(originalName: "name") var title: String
init(title: String) {
self.title = title
}
}
}
Migration plan:
enum TripsMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[TripsSchemaV1.self, TripsSchemaV2.self]
}
static var stages: [MigrationStage] {
[migrateV1toV2]
}
static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: TripsSchemaV1.self, toVersion: TripsSchemaV2.self)
}
And finally the usage:
@main
struct TripsApp: App {
let container: ModelContainer
init() {
do {
container = try ModelContainer(for: [Trip.self], migrationPlan: TripsMigrationPlan.self, ModelConfiguration(for: [Trip.self]))
} catch {
fatalError("Could not initialize the container.")
}
}
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(container)
}
}
}
When I run the app, all my data for the Trips is gone and I get the following message on the output window.
Unresolved error loading container Error Domain=NSCocoaErrorDomain Code=134504 "Cannot use staged migration with an unknown coordinator model version." UserInfo={NSLocalizedDescription=Cannot use staged migration with an unknown coordinator model version.}
Any ideas?
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 marked as Apple Recommended
Hi,
has anybody managed to get two sqlite stores working? If I define the stores with a configuration for each it seems like that only the first configuration and and therefore the store is recognised.
This is how I define the configuration and container:
import SwiftData
@main
struct SwiftDataTestApp: App {
var modelContainer: ModelContainer
init() {
let fullSchema = Schema([
SetModel.self,
NewsModel.self
])
let setConfiguration = ModelConfiguration(
"setconfig",
schema: Schema([SetModel.self]),
url: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("Sets.sqlite"),
readOnly: false)
let newsConfiguration = ModelConfiguration(
"newsconfig",
schema: Schema([NewsModel.self]),
url: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("News.sqlite"),
readOnly: false)
modelContainer = try! ModelContainer(for: fullSchema, configurations: [setConfiguration,newsConfiguration])
}
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(modelContainer)
}
}
ContentView is just a basic TabView with a tab for news and a tab for sets.
If I run the program this way the sets tab is shown correctly but switching to News fails. If I change the order of the configurations and write the one for news first like this:
modelContainer = try! ModelContainer(for: fullSchema, configurations: [newsConfiguration, setConfiguration])
then the news tab is shown correctly and switching to sets tab fails.
NewsModel and SetModel only differ in the class name
Import Foundation
import SwiftData
@Model
public class NewsModel{
public var name: String
init(name: String) {
self.name = name
}
}
Also the tab content differs only for referencing the respecting model and the name:
import SwiftData
struct NewsTab: View {
@Query private var news: [NewsModel]
@Environment(\.modelContext) private var modelContext
var body: some View {
ScrollView{
LazyVStack{
ForEach(news){actNews in
Text("Hello, News \(actNews.name)")
}
}
.onAppear {
let news = NewsModel(name: "News from \(Date())")
modelContext.insert(news)
try! modelContext.save()
}
}
}
}
The error message is "NSFetchRequest could not locate an NSEntityDescription for entity name 'NewsModel'" (and SetsModel respectively when change the order of the configuration)
Do I explicitly need to tell the modelContext which configuration it should use or is this done automatically?
I'm a little lost here and hope someone can help me.
Best regards,
Sven
Post not yet marked as solved
It's been frustrating to solve this error. My iOS device and Xcode are fully updated. I can easily run app on simulator, but issue happens on my iPhone.
dyld[23479]: Symbol not found: _$s9SwiftData12ModelContextC6insert6objectyx_tAA010PersistentC0RzlFTj
Referenced from: <6FC773BB-E68B-35A9-B334-3FFC8B951A4E> Expected in: /System/Library/Frameworks/SwiftData.framework/SwiftData
Post not yet marked as solved
There is a new Relationship macro in Xcode Beta 6. The macro includes two new arguments: minimumModelCount and maximumModelCount. I wonder if anyone knows what these values are for and if there is another change under the hood.
Relationship(
_ options: PropertyOptions...,
deleteRule: Schema.Relationship.DeleteRule = .nullify,
minimumModelCount: Int? = 0,
maximumModelCount: Int? = 0,
originalName: String? = nil,
inverse: AnyKeyPath? = nil,
hashModifier: String? = nil
)
Post not yet marked as solved
This approach worked in Beta 5, but does not work in Betas 7 & 8. (I skipped Beta 6, so I don't know if it worked then). I'm not sure if it's a SwiftData bug or a mistake on my part since the API has changed since the WWDC video. (I opened Apple Feedback: FB13120831)
I am trying to implement a cascade delete on a many to one relationship. See the two models below. When I deleted the Recipe Model object, I expect that any of the FoodMenus that have that recipe will also be deleted. But they are not. The Recipe is deleted and the FoodMenu is still there.
When I put a deleteRule: .cascade on the FoodMenu.recipe, the cascade does work. The Menu and the Associated recipe are both deleted. But that's not the behavior I want.
@Model
final class Recipe {
var name: String
var id: UUID
@Relationship(deleteRule: .cascade, inverse: \FoodMenu.recipe)
var menus: [FoodMenu]?
init(name: String, id: UUID, menus: [FoodMenu]? = []) {
self.name = name
self.id = id
self.menus = menus
}
}
@Model
final class FoodMenu {
var name: String
var id: UUID
var recipe: Recipe? = nil
//I believe the below definition should be the same behavior as above and it works as expected. relationship is nullified when the FoodMenu is deleted. Recipe left in place.
// @Relationship (deleteRule: .nullify, inverse: \Recipe.menus)
// var recipe: Recipe? = nil
init(name: String, id: UUID) {
self.name = name
self.id = id
}
}
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
Like the title says, I've realised that when I try to use filter or sort on properties that aren't standard supported data types i.e. Using a transformable or a value type like an enum, I seem to be getting the following crash...
SwiftData/DataUtilities.swift:1140: Fatal error: Unexpected type for Expansion: Optional<UIColor>
Xcode expands and shows me when trying to access the wrapped value it's crashing. I'm assumung that the query property wrapper can't handle these custom data types
@Query private var items: [Item]
{
get {
_items.wrappedValue <--- Crash here
}
}
Which seems to be pointing to a transferable property in one of my models. Below are my two models i'm using.
enum Priority: Int, Codable, Identifiable, CaseIterable {
case low
case medium
case high
var title: String {
switch self {
case .low:
return "Low"
case .medium:
return "Medium"
case .high:
return "High"
}
}
var image: Image? {
switch self {
case .medium:
return Image(systemName: "exclamationmark.2")
case .high:
return Image(systemName: "exclamationmark.3")
default:
return nil
}
}
var id: Self { self }
}
@Model
final class Item: Codable {
var title: String
@Attribute(originalName: "timestamp")
var dueDate: Date
var isCompleted: Bool
var isFlagged: Bool = false
var isArchived: Bool = false
var isCritical: Bool?
var priority: Priority?
@Relationship(deleteRule: .nullify, inverse: \Category.items)
var category: Category?
@Attribute(.externalStorage)
var image: Data?
enum CodingKeys: String, CodingKey {
case title
case timestamp
case isCritical
case isCompleted
case category
case imageName
}
init(title: String = "",
dueDate: Date = .now,
priority: Priority? = nil,
isCompleted: Bool = false) {
self.title = title
self.dueDate = dueDate
self.priority = priority
self.isCompleted = isCompleted
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.title = try container.decode(String.self, forKey: .title)
self.dueDate = Date.randomDateNextWeek() ?? .now
self.isCompleted = try container.decode(Bool.self, forKey: .isCompleted)
self.category = try container.decodeIfPresent(Category.self, forKey: .category)
if let imageName = try container.decodeIfPresent(String.self, forKey: .imageName),
let imageData = UIImage(named: imageName) {
self.image = imageData.jpegData(compressionQuality: 0.8)
}
if let isCritical = try container.decodeIfPresent(Bool.self, forKey: .isCritical),
isCritical == true {
self.priority = .high
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(title, forKey: .title)
try container.encode(dueDate, forKey: .timestamp)
try container.encode(isCompleted, forKey: .isCompleted)
try container.encode(category, forKey: .category)
}
}
@Model
class Category: Codable {
@Attribute(.unique)
var title: String
var items: [Item]?
@Attribute(.transformable(by: ColorValueTransformer.self))
var color: UIColor?
init(title: String = "",
color: UIColor) {
self.title = title
self.color = color
}
enum CodingKeys: String, CodingKey {
case title
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.title = try container.decode(String.self, forKey: .title)
self.color = UIColor(possibleColors.randomElement()!)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(title, forKey: .title)
}
}
And below is an example of me sorting based on my enum (Priority) & Relationship (Category name)
func sort() -> [SortDescriptor<Item>]{
switch self {
case .title:
[SortDescriptor(\Item.title)]
case .date:
[SortDescriptor(\Item.dueDate)]
case .category:
[SortDescriptor(\Item.category?.title)]
case .priority:
[SortDescriptor(\Item.priority?.rawValue)]
}
}
And a filter example below creating a predicate that we will execute to return and matches found in the title or category title
let highPriority = Priority.high
if let query {
return #Predicate {
$0.priority == highPriority &&
($0.title.contains(query) || $0.category?.title.contains(query) == true) &&
$0.isArchived == false
}
}
I'm pretty sure this is a SwiftData bug since when using strings, bools and dates it's all fine using anything outside of that box causes these crashes...