Suppose I have two iPhones that are offline. On the first iPhone, at 1 PM, I create a Person object with the details: name: "John", lastName: "Smith", and age: 40. Then, on the second iPhone, which is also offline, I also create Person object at 2 PM with the same name: "John" and lastName: "Smith", but with a different age: 30.
Both iPhones come online at 3 PM and sync with CloudKit. I would expect CloudKit to reconcile these two records and end up with a single record—specifically, Person(name: "John", lastName: "Smith", age: 30), assuming a "last writer wins" approach.
Any guidance or best practices for handling this situation would be greatly appreciated!
My idea is that I could generate a 128bit UUID as hash from first name and last name and then I would have to force this UUID to be used as recordName in CKRecord as this would trigger a conflict on CloudKit side and prevent two instance to be created. But how do I accomplish this with SwiftData or CoreData?
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
Dear all,
I'm developing an application with SwiftData for Mac and since the beginning I'm experiencing issues in opening sheets.
In particular, I have a view where I'm trying to open a sheet which is called TrainingAttendanceView, but it not working at all. When I click on it, the application is stuck and not working anymore. Debugger is not retrieving anything and I don't have any clue on what to do.
Could you please let me know what I'm doing wrong or if there is any possible workaround?
Thanks in advance for the support,
A.
Here the code of the view where I'm calling the sheet:
import SwiftUI
import SwiftData
struct CalendarView: View {
@Environment(\.modelContext) private var context
@ObservedObject var season: Season
@Query var trainings: [Training]
@State private var isAddingTraining = false
@State private var trainingToEdit: Training?
@State private var trainingToDelete: Training?
@State private var trainingForAttendance: Training?
@State private var showAlert = false
@State private var isShowingAttendance = false
var body: some View {
VStack {
ScrollView {
VStack(alignment: .leading, spacing: 12) {
ForEach(months, id: \.self) { month in
monthView(for: month)
}
}
.padding()
}
.alert(isPresented: $showAlert) {
Alert(
title: Text("Conferma cancellazione"),
message: Text("Sei sicuro di voler cancellare questo allenamento?"),
primaryButton: .destructive(Text("Elimina")) {
if let training = trainingToDelete {
deleteTraining(training)
}
},
secondaryButton: .cancel {
trainingToDelete = nil
}
)
}
.sheet(isPresented: $isAddingTraining) {
if let trainingToEdit = trainingToEdit {
EditTrainingView(isEditingTraining: $isAddingTraining, season: season, training: trainingToEdit)
} else {
AddTrainingView(isAddingTraining: $isAddingTraining, season: season)
}
}
.sheet(isPresented: $isShowingAttendance) {
if let training = trainingForAttendance {
TrainingAttendanceView(season: season, trainingDate: training.date, training: training)
}
}
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button(action: {
isAddingTraining = true
trainingToEdit = nil
}) {
Text("+ Add Training")
.foregroundColor(.blue)
}
}
}
}
}
private var trainingsByMonth: [String: [Training]] {
...
}
private var months: [String] {
...
}
private func monthIndex(for monthString: String) -> String? {
...
}
private func deleteTraining(_ training: Training) {
...
}
private func monthView(for month: String) -> some View {
VStack(alignment: .leading, spacing: 8) {
Text(month)
.font(.headline)
.padding(8)
.background(Color.clear)
if let monthIndex = monthIndex(for: month), let trainingsInMonth = trainingsByMonth[monthIndex] {
if trainingsInMonth.isEmpty {
Text("Non ci sono eventi per questo mese")
.padding(8)
} else {
ForEach(trainingsInMonth, id: \.self) { training in
HStack(alignment: .center, spacing: 8) {
Rectangle()
.fill(Color.green)
.frame(width: 4)
VStack(alignment: .leading, spacing: 4) {
Text("Allenamento")
.font(.subheadline)
.bold()
Text(training.date, style: .date)
.font(.footnote)
Text("Ore: \(training.startTime, style: .time) - \(training.endTime, style: .time)")
.font(.footnote)
}
Spacer()
HStack(spacing: 12) {
Button(action: {
trainingToEdit = training
isAddingTraining = true
}) {
Image(systemName: "pencil")
}
.buttonStyle(BorderlessButtonStyle())
.foregroundColor(.blue)
Button(action: {
trainingForAttendance = training
isShowingAttendance = true
}) {
Image(systemName: "person.3.fill")
}
.buttonStyle(BorderlessButtonStyle())
.foregroundColor(.blue)
Button(action: {
trainingToDelete = training
showAlert = true
}) {
Image(systemName: "trash")
.foregroundColor(.red)
}
.buttonStyle(BorderlessButtonStyle())
}
.frame(width: 100, alignment: .center)
}
}
}
} else {
Text("Non ci sono eventi per questo mese")
.padding(8)
}
}
.padding()
}
}
While here the starting code of the TrainingAttendanceView:
import SwiftData
struct TrainingAttendanceView: View {
@Environment(\.modelContext) private var context
@ObservedObject var season: Season
var trainingDate: Date
@ObservedObject var training: Training
@State private var attendance: [PlayerAttendance] = []
@Query private var players: [Player]
init(season: Season, trainingDate: Date, training: Training) {
self.season = season
self.trainingDate = trainingDate
self.training = training
...
Hi,
I had a SwiftData model and it was working fine, I had few records in it, but when I added to its Module file few extra properties I started to get the below error ! how to fix this ?
"Thread 1: Fatal error: failed to find a currently active container for Patient"
Hi,
I'm struggling with SwiftData and the components for migration and could really use some guidance. My specific questions are
Is it possible to go from an unversioned schema to a versioned schema?
Do all @Model classes need to be converted?
Is there one VersionedSchema for the entire app that handles all models or one VersionedSchema per model?
What is the relationship, if any, between the models given to ModelContainer in a [Schema] and the models in the VersionedSchema in a [any PersistentModel.Type]
I have an app in the AppStore. I use SwiftData and have four @Models defined. I was not aware of VersionedSchema when I started, so they are unversioned. I want to update the model and am trying to convert to a VersionedSchema. I've tried various things and can't even get into the migration plan yet. All posts and tutorials that I've come across only deal with one Model, and create a VersionedSchema for that model.
I've tried to switch the one Model I want to update, as well as switching them all. Of course I get different errors depending on what configuration I try.
It seems like I should have one VersionedSchema for the app since there is the static var models: [any PersistentModel.Type] property. Yet the tutorials I've seen create a TypeNameSchemaV1 to go with the @Model TypeName.
Which is correct? An AppNameSchemaV1 which defines four models, or four TypeNameSchemaV1?
Any help will be much appreciated
When I try to delete items from my list stored with swift data, it instantly makes crash my app with this error message: SwiftData/BackingData.swift:482: Fatal error: Never access a full future backing data - PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://03DEFFA9-87EF-4E13-9448-946D9EBC17B6/Exercise/p8), implementation: SwiftData.PersistentIdentifierImplementation) with Optional(0252D555-649A-45B2-954C-7DD62A6DBAE4)
import SwiftUI
import SwiftData
struct WorkoutsView: View {
@Environment(\.modelContext) var modelContext
@Query(sort: [
SortDescriptor(\Workout.name),
SortDescriptor(\Workout.difficulty),
SortDescriptor(\Workout.duration)
]) var workouts: [Workout]
@State private var isEditing = false
@State private var showingAddScreen = false
var body: some View {
NavigationStack {
List {
ForEach(workouts) { workout in
//design purpose code
}
.onDelete(perform: deleteWorkouts)
}
.navigationTitle("Workouts")
.toolbar {
ToolbarItem(placement: .topBarLeading) {
EditButton()
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
showingAddScreen = true
}) {
Image(systemName: "plus")
}
}
}
.sheet(isPresented: $showingAddScreen) {
AddWorkoutView()
}
}
}
func deleteWorkouts(at offsets: IndexSet) {
for offset in offsets {
let workout = workouts[offset]
modelContext.delete(workout)
}
}
}
Dear all,
I'm going out of mind with the following issue. I have a view where I'm selecting a date through a datepicker. Then I'm inserting some other data and then I'm trying to save, see private func saveTraining(). But the date which is used to save the training is always one day before the selected date and more than this, I'm not able to save it without time. As I have then a calendar where the saved trainings need to be displayed, I'm not able to match it.
Did anybody already face this issue? How can I solve it?
I'm reporting here the code of the view where you can also find the checks I put to verify values/ dates:
import SwiftData
import AppKit
struct AddTrainingView: View {
@Environment(\.modelContext) private var context
@Binding var isAddingTraining: Bool
@ObservedObject var season: Season
@Binding var selectedDate: Date
@State private var trainingStartTime = Date()
@State private var trainingEndTime = Date()
@State private var trainingConditionalGoal = ""
@State private var trainingTacticalGoal = ""
@State private var trainingExercises: [TrainingExercise] = []
@State private var showExercisePicker = false
@State private var currentTraining: Training?
init(isAddingTraining: Binding<Bool>, selectedDate: Binding<Date>, season: Season, currentTraining: Training? = nil) {
self._isAddingTraining = isAddingTraining
self._selectedDate = selectedDate
self.season = season
self._currentTraining = State(initialValue: currentTraining)
if let training = currentTraining {
self._trainingStartTime = State(initialValue: training.startTime)
self._trainingEndTime = State(initialValue: training.endTime)
self._trainingConditionalGoal = State(initialValue: training.conditionalGoal)
self._trainingTacticalGoal = State(initialValue: training.tacticalGoal)
self._trainingExercises = State(initialValue: training.trainingExercises)
}
}
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Aggiungi Allenamento")
.font(.title)
.bold()
.padding(.top)
VStack(alignment: .leading) {
Text("Data allenamento:")
DatePicker("", selection: $selectedDate, displayedComponents: .date)
.datePickerStyle(.field)
}
.padding(.bottom, 10)
...
Button("Salva") {
saveTraining()
isAddingTraining = false
dismiss()
}
.buttonStyle(.borderedProminent)
.tint(.blue)
Button("Visualizza PDF") {
createPDF()
}
.buttonStyle(.borderedProminent)
.tint(.blue)
Spacer()
}
.padding(.bottom)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
private func saveTraining() {
// Creiamo un'istanza del calendario corrente
var calendar = Calendar.current
calendar.timeZone = TimeZone.current // Assicuriamoci di utilizzare il fuso orario locale
// Estrarre solo i componenti di data dalla data selezionata
let components = calendar.dateComponents([.year, .month, .day], from: selectedDate)
// Creiamo una nuova data con i soli componenti di anno, mese e giorno
guard let truncatedDate = calendar.date(from: components) else {
print("Errore nella creazione della data troncata")
return
}
// Stampa di debug per verificare la data selezionata e quella troncata
print("Data selezionata per l'allenamento: \(selectedDate)")
print("Data troncata che verrà salvata: \(truncatedDate)")
let newTraining = Training(
date: truncatedDate,
startTime: trainingStartTime,
endTime: trainingEndTime,
conditionalGoal: trainingConditionalGoal,
tacticalGoal: trainingTacticalGoal,
season: season
)
// Verifica che la data sia correttamente impostata
print("Data che verrà salvata: \(newTraining.date)")
newTraining.trainingExercises = trainingExercises
context.insert(newTraining)
do {
try context.save()
print("Allenamento salvato correttamente.")
} catch {
print("Errore nel salvataggio: \(error.localizedDescription)")
}
}
private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateStyle = .short
return formatter
}
private var timeFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.timeStyle = .short
return formatter
}
}
}
Example: when I'm selecting 2023-08-21, the debugger retrieves me following data:
Data selezionata per l'allenamento: 2023-08-20 22:00:00 +0000
Data troncata che verrà salvata: 2023-08-20 22:00:00 +0000
Data che verrà salvata: 2023-08-20 22:00:00 +0000
Allenamento salvato correttamente.
Hi! I'm investigating some crashes that seem to be related to ModelContext.autosaveEnabled^1. I don't have a very clean repro test case at this time… but I seem to be seeing crashes when a SwiftUI app moves to the background. I am testing an app built for macOS 14.6.1. I am building from Xcode_16_beta_5.
My app is not using a mainContext. My app is building a ModelActor that is running on a background thread (off main). The modelContext inside my ModelActor is set with autosaveEnabled equal to true. The mutations on my state are not being explicitly saved (I am waiting for the system to save automatically).
My guess (so far) is that transitioning into the background from SwiftUI is kicking off some kind of logic that is specifically being tied to the main thread… but this is causing problems when my modelContext is created from a background thread. My understanding was that ModelActor could help to defend against threading problems… but this might be a different problem that I did not expect.
I am unblocked for now by turning off autosaveEnabled (and manually saving from my ModelActor). That fixes the crashes. Any more thoughts or insight about what could be causing these crashes when my app transitions into the background? Thanks!
Thread 1 Queue : com.apple.main-thread (serial)
#0 0x000000023108beb8 in ___lldb_unnamed_symbol2827 ()
#1 0x000000023108ef30 in ___lldb_unnamed_symbol2847 ()
#2 0x000000023108eca8 in ___lldb_unnamed_symbol2845 ()
#3 0x000000019bac6144 in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
#4 0x000000019bb5a3d8 in ___CFXRegistrationPost_block_invoke ()
#5 0x000000019bb5a320 in _CFXRegistrationPost ()
#6 0x000000019ba94678 in _CFXNotificationPost ()
#7 0x000000019cbb12c4 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#8 0x000000019f489408 in -[NSApplication _handleDeactivateEvent:] ()
#9 0x000000019fb24380 in -[NSApplication(NSEventRouting) sendEvent:] ()
#10 0x000000019f771d9c in -[NSApplication _handleEvent:] ()
#11 0x000000019f322020 in -[NSApplication run] ()
#12 0x000000019f2f9240 in NSApplicationMain ()
#13 0x00000001c74c73b8 in ___lldb_unnamed_symbol83060 ()
#14 0x00000001c7c30ddc in ___lldb_unnamed_symbol132917 ()
#15 0x00000001c802be0c in static SwiftUI.App.main() -> () ()
Thread 5 Queue : NSManagedObjectContext 0x6000009c38e0 (serial)
#0 0x000000019ba66f94 in constructBuffers ()
#1 0x000000019ba65e30 in _CFURLCreateWithURLString ()
#2 0x000000019bad6e7c in _CFURLComponentsCopyURLRelativeToURL ()
#3 0x000000019cbde864 in -[__NSConcreteURLComponents URL] ()
#4 0x000000019d3782f8 in -[NSURL(NSURL) initWithString:relativeToURL:encodingInvalidCharacters:] ()
#5 0x000000019cbdd4d4 in +[NSURL(NSURL) URLWithString:relativeToURL:] ()
#6 0x00000001a23feef0 in -[NSTemporaryObjectID URIRepresentation] ()
#7 0x00000002310e0878 in ___lldb_unnamed_symbol4176 ()
#8 0x00000002310ef480 in ___lldb_unnamed_symbol4401 ()
#9 0x00000002310eb6e0 in ___lldb_unnamed_symbol4385 ()
#10 0x00000002310a22b4 in ___lldb_unnamed_symbol3130 ()
#11 0x00000002310ed4e8 in ___lldb_unnamed_symbol4390 ()
#12 0x00000002310883dc in ___lldb_unnamed_symbol2799 ()
#13 0x0000000231087edc in ___lldb_unnamed_symbol2798 ()
#14 0x000000023109fd24 in ___lldb_unnamed_symbol3021 ()
#15 0x0000000231086acc in ___lldb_unnamed_symbol2784 ()
#16 0x00000001a2392144 in developerSubmittedBlockToNSManagedObjectContextPerform ()
#17 0x00000001a2392004 in -[NSManagedObjectContext performBlockAndWait:] ()
#18 0x00000002310879ac in ___lldb_unnamed_symbol2797 ()
Posting here to see if folks have workarounds or if I have a misunderstanding of SwiftData supported types.
In adopting SwiftData, I have swiftData properties of collection type (Array or Set - both have this issue). E.g:
@Model
final class Item {
var timestamp: Date
var strings = ["aa", "bb"]
var display: String {
strings.joined(separator: " ")
}
init(timestamp: Date) {
self.timestamp = timestamp
}
}
So far in development I haven't had issues on iOS 17, but on the iOS 18 betas 4-5 the app logs show the following error:
"fault: Could not materialize Objective-C class named "Array" from declared attribute value type "Array<String>" of attribute named strings"
It happens immediately in my app when creating an object with a collection attribute.
In a minimal test example, the error log appears only after a few minutes and doesn't seem to affect the template app's basic functionality.
Anyone else running into this?
Was filed as FB14397250
Hi! I am seeing some unexpected behavior when attempting to create a Model instance with a variable named updated. I start with a simple Model:
@Model final public class Item {
var timestamp: Int
var updated: Int
public init(timestamp: Int = 1, updated: Int = 1) {
self.timestamp = timestamp
self.updated = updated
}
}
I then attempt to create an item instance:
func main() throws {
let schema = Schema([Item.self])
let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(
for: schema,
configurations: configuration
)
let modelContext = ModelContext(container)
let item = Item()
print(item.timestamp)
print(item.updated)
}
try main()
The value of item.timestamp is printing as 1 and the value of item.updated is printing as 0.
I have no idea what could be causing that to happen… why would both those values not be printing as 1? Is there some private API that is somehow colliding with the (public) updated variable and causing the item instance to report back with a value of 0? Is there documentation warning engineers that a variable named updated is off-limits and results in undefined behavior?
I can fix that by renaming the variable:
@Model final public class Item {
var timestamp: Int
var updatedTimestamp: Int
public init() {
self.timestamp = 1
self.updatedTimestamp = 1
}
}
I am unblocked on this (because renaming the variable seems to work fine)… but is there any insight on why this might be happening in the first place? I am building from Xcode_16_beta_5. Thanks!
Hi,
I've run into two problems using SwiftData in iOS 18 that are total show-stoppers for my app, causing it to run out of memory and be killed by the system. The same app runs fine on iOS 17.
The two problems are inter-related in a way I can't exactly diagnose, but are easy to reproduce.
Problem #1: Calling .count on the array that represents a relationship or Query causes the whole array of objects to be loaded into memory.
Problem #2: When a @Model object is loaded, properties that are declared with .externalStorage are loaded unnecessarily, and use tons of memory.
It's possible that #1 is normal behavior, exacerbated by #2.
I've written a test app that demonstrates the extreme difference in memory usage between the OS Versions. It uses a typical navigation pattern, with content counts on the left-side view. Each item has one thumbnail and one large image in .externalStorge. GitHub Source
When populated with 80 items, each containing one thumbnail and one large image in .externalStorge, the app launches in 17.5 using 29mb of memory. On iOS 18, in the same conditions, 592 mb.
When the first folder is selected, causing a list of thumbnails to load, iOS 17 uses just 86mb. iOS 18 uses 599mb, implying that all image data has already been loaded.
So I'm asking for help from Apple or the Community in finding a workaround. I've been advised that finding a workaround may be necessary, as this may not be addressed in 18.0.
Thanks in advance for any insight.
Radars: FB14323833, FB14323934
(See attached images, or try it yourself)
(You may notice in the 18.0 screenshots that the item counts don't add up right. That's yet another 18.0-SwiftData anomaly regarding relationships that I haven't tackled yet, but is also demonstrated by the sample app.)
Say you have a SwiftData object that doesn't allow optionals:
@Model
class MySet: Identifiable {
var id: UUID
var weight: Int
var reps: Int
var isCompleted: Bool
var exercise: Exercise
Then you get from your MySet data a list of these MySets and append them into a State:
@State var sets: [MySet]
if let newSets = exercise.sets { //unwrapping the passed exercises sets
if (!newSets.isEmpty) { //we passed actual sets in so set them to our set
sets = newSets
}
And you use that State array in a ForEach and bind the Textfield directly to the data like so:
ForEach($sets){ $set in
TextField("\(set.weight)", value: $set.weight, formatter: NumberFormatter())
.keyboardType(.decimalPad)
TextField("\(set.reps)", value: $set.reps,formatter: NumberFormatter())
.keyboardType(.decimalPad)
}
This will bind whatever is written into the TextField directly to the SwiftData object which is a problem because say you have 50 written and you want to change it to 60 you need to be able to clear the 50 to write the 60 and since the SwiftData object doesn't allow nil it will allow you to remove the 0 but not the 5. Is there anyway to remedy this without having the swiftData object allow optionals for example catching the clearing of the TextField and making it 0 instead of nil when its cleared?
Recently I've been working on a demo project called iLibrary. The main goal was to learn more about CloudKit and SwiftData. After a while I noticed that there were some hangs/freezes when running the app in debug mode.
I first tried this with Xcode 15.4 and iOS 17.5. Here the hang only appears at the beginning, but only for a few seconds. But when I exit debug mode, there are no more hangs.
With Xcode 16 beta 4 and iOS 18 it looks completely different. In this case, the hangs and freezes are always present, whether in debug mode or not. And it's not just at the beginning, it's throughout the app. I'm aware that this is still a beta, but I still find this weird. And when I profile this I see that the main thread gets quite overloaded. Interestingly, my app doesn't have that many operations going on. So I guess something with the sync of SwiftData or my CloudKitManger where I fetch some records from the public database is not running fine.
Lastly, I wanted to delete the iCloud app data. So I went to Settings and tried to delete it, but it didn't work. Is this normal?
Does anyone have any idea what this could be? Or has anyone encountered this problem as well? I'd appreciate any support.
My project: https://github.com/romanindermuehle/iLibrary
Hi, first time posting here (sorry if it's a bit long).
I'm using MacBook Pro 16-inch 2021 (M1), macOS 14.5, Xcode 15.4.
I'm somewhat new to SwiftUI + SwiftData, as my macOS development experience is from (way too) many years ago.
I'm developing a SwiftData application, which (so far) is going fairly smoothly. I've reduced my application code to a minimum by commenting out most of it, and I still see the same error message.
I've poked around the Internet for a while now, looking for any hints, but nothing seems to address this specific issue (most talk about other views/types, and in some of those cases the problem is readily apparent).
Here's the (reduced) code for the view in question (it's the primary view in a single-window app; I've barely started so there's not much else there):
// Model/Config.swift
@Model
final class Config: Identifiable {
@Attribute(.unique)
var uuid: UUID = UUID()
// ...
var id: UUID { // for the Identifiable protocol
uuid
}
}
// Views/ContentView.swift
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Config]
@State private var theSelection: Config.ID?
var body: some View {
NavigationSplitView {
List(items, selection: $theSelection) { item in
NavigationLink {
Text("UUID: \(item.uuid)")
} label: {
Text(item.uuid.uuidString)
.font(.title2)
}
}
} detail: {
Text("Select an item")
}
}
}
Initially when I run the app, no (existing) items are selected. When I click to choose one of the items (doesn't matter which one), I get the error message from the post title, which I'll repeat here:
List with selection: SelectionManagerBox tried to update multiple times per frame.
It only appears the one time. My item deletion code (not shown above) resets theSelection = nil (by the time I get to this code, the problem has already occurred, so it can't be this). Clicking to make a subsequent selection does not trigger the message again.
Other than this message, the view seems to be operating as expected.
I also tried:
remove selection from List()
problem goes away
change selection type to UUID? and List(id: \.uuid), remove Identifiable and id from Config
problem persists
change selection type to Config? and List(id: \.self)
problem persists
change the List to have just the selection, and use ForEach to build the items' views
problem persists
I do see other messages (which other posts indicate are likely noise), but those are typically coloured yellow ("warning"?). The message I'm posting about is shown in red/purple ("error?").
I'm not too worried for now given that the view seems to be behaving OK otherwise, but my concern is whether this will come back to bite me down the road.
Thanks for your time and attention.
Hello, I'm having a problem with SwiftData that I can't find a solution for. Every change made to the firstArray updates the interface. However, the changes I make on secondArray do not update the interface. The changes on secondArray are saved but the UI is not updated.
(I can see that the interface is updated by the text giving the number of elements in the array. )
Model:
import Foundation
import SwiftData
@Model
final class Item {
var firstArray: [String]
var itemDetail: ItemDetail
init(firstArray: [String], itemDetail: ItemDetail) {
self.firstArray = firstArray
self.itemDetail = itemDetail
}
}
@Model
class ItemDetail {
var secondArray: [String]
init(secondArray: [String]) {
self.secondArray = secondArray
}
}
Content View:
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
NavigationLink("Item") {
ItemDetailView(item: item, itemDetail: item.itemDetail)
}
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Add", systemImage: "plus") {
let item = Item(firstArray: ["Mehmet", "Fırat", "Şirin"], itemDetail: ItemDetail(secondArray: ["Mehmet", "Fırat", "Şirin"]))
modelContext.insert(item)
}
}
ToolbarItem(placement: .topBarLeading) {
Button("Delete", systemImage: "trash", role: .destructive) {
try? modelContext.delete(model: Item.self)
}
.tint(.red)
}
}
}
}
}
Detal View:
import SwiftUI
struct ItemDetailView: View {
let item: Item
let itemDetail: ItemDetail // for Version 3
var body: some View {
List {
//MARK: Version 1
Text(item.firstArray.count.formatted())
Section {
ForEach(item.firstArray, id: \.self) {
Text($0)
}
.onDelete {
item.firstArray.remove(atOffsets: $0)
}
}
//MARK: Version 2
Text(item.itemDetail.secondArray.count.formatted())
Section {
ForEach(item.itemDetail.secondArray, id: \.self) {
Text($0)
}
.onDelete {
item.itemDetail.secondArray.remove(atOffsets: $0)
}
}
Button("Delete All") {
item.itemDetail.secondArray = []
}
//MARK: Version 3
Text(itemDetail.secondArray.count.formatted())
Section {
ForEach(itemDetail.secondArray, id: \.self) {
Text($0)
}
.onDelete {
itemDetail.secondArray.remove(atOffsets: $0)
}
}
Button("Delete All") {
itemDetail.secondArray = []
}
}
}
}
Try the versions with only one on the screen.
In version 1 everything works fine. In version 2 the deletion works but the interface is not updated. In version 3 everything works fine. I don't think version 3 is a very correct method so I am waiting for your ideas and solutions. Thanks for all the answers.
My app is using SwiftData with CloudKit integration. Everything at the moment is working fine. I have a struct that saves Data as an optional. This is Data related to an Image. It saves and loads as expected. When I disconnect my phone from wifi or my phone network, the image still loads. I'm assuming that means the Data is being stored locally on the phone as well. Is there a way to display what's stored locally to the user inside the application?
Edit: I've realized that CloudKit is saying the data is too large, but the images are still being saved. Does that mean they're only locally being saved?
Hello!
I apologize in advance if I chose the wrong topic for my question, this is my first time on this forum.
I am a novice developer and I am creating an application. I use Swift + SwiftUI, but I ran into such a problem that I have nowhere to store my data and I do not know how to store it correctly. I know that there is a SwiftData framework that is used to work with data, but I don't understand the documentation.
Please be understanding. How do I start learning SwiftData? What topics should be studied? What is the order of studying topics? Thank you all in advance!
Some of my models have many-to-many relationships. For example, when I add a file to a directory, a model is created from that in addition to any relationships it may contain.
I’ve incorporated SwiftData History into my front end and backend projects and it’s able to show me what has been inserted, updated, and even deleted after the file is removed from the directory. Which only returns the identifiers I’ve set to become tombstone values. All working as expected and my client can now sync with the server.
I can add and remove the same file repeatedly and I’m able to retrieve all the transactions.
However if I add another file and then fetch transactions, it crashes at .fetchHistory(_:). The errors say they cannot find the property of a model it has a many-to-many relationship with.
I omitted appending any relationships, but the errors start pointing to properties belonging to the model itself.
I’ve only managed to get this functioning by setting the @Relationship macro to a single model. Previously, I had this macro with its delete rule and inverse on other types. But doing so would crash the same way immediately and wouldn’t let me fetch history at all.
Since it crashes at fetching the history, I’m unable to proceed and the options appear to be limited for what I can do before I fetch them.
Does SwiftData History not work with many-to-many relationships or is this a bug?
I am trying to use the ModelContainer's "delete" function to delete all instances of a model but I'm getting an error related to my relationships:
Constraint trigger violation: Batch delete failed due to mandatory OTO nullify inverse on LeagueSeasonRanking/golfer
I do have a relationship on Golfer, a toMany relationship to LeagueSeasonRanking which is marked with a cascade delete rule... I would expect that to take care of things and cascade along but it seems to not work. Is that a bug?
Hi,
I know how to sort SwiftData records based on one of its properties such as name, but how to sort based on recent updated records ? like in Apple Notes App ?
Kind Regards
I'm just starting to learn iOS app development and I'm currently using SwiftData. The main app is working fine, and now I've added a Widget to use data from the main app. I've already enabled App Groups and want to reference the shared model entities from the main app, but I'm getting an error saying "can't find type in scope." What additional configurations do I need to make in order to properly reference the same entities? I've seen many example codes that have a "Shared" folder, but even after creating one and moving the files into it, I'm still unable to use them properly. I must be missing some configuration, right?
Also, there's another issue: when debugging the Widget, I keep getting the following error. What could be causing this?
SendProcessControlEvent:toPid: encountered an error: Error Domain=com.apple.dt.deviceprocesscontrolservice Code=8 "Failed to show Widget 'XXXX-Widget' error: Error Domain=FBSOpenApplicationServiceErrorDomain Code=1 "The request to open "com.apple.springboard" failed."