Hello I have a TestFlight tester getting a random repeated crash when the app is interacting with core data. Every time it crashes we get the call stack like below from line 6 stating -NSManagedObject _processRecentChanges.
Searching for _sharedIMPL_setvfk_core it seems to indicate a multithreading issue but my managedObjectContext is initialized with main queue concurrency.
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil)
{
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSMainQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext;
}
When I pulled the cashpoint in to the Xcode project everything appears to be running on the main thread.
I can't seem to find documentation on what might be causing the issue. Any pointers would be appreciated. The app is compiled on Xcode 15 targeting iOS 15. Users device is iOS 17.3.1.
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
Hey,
I'm currently working on adding CloudKit support to the GRDB SQLite database in my app. CKSyncEngine, though still a bit tricky to wrap your head around, is amazing!
I have most of the basic setup implemented and some very easy cases already work, which is really exciting!
However, I do have some questions regarding data consistency across devices. I'm not sure though, that these questions are actually "correct" to ask. Maybe my entire approach is inherently flawed.
Say we add two records to the pending changes of the sync engine:
// I'm simplifying CKRecord.ID to be a String here
syncEngine.state.add(pendingRecordZoneChanges: [.saveRecord("1"), .saveRecord("2")]
Let's also say that both records are tightly connected. For example, they could be in a one-to-one relationship and must always be added to the database together because the app relies on the existence of either none or both.
After that call, at some later point, the system will call the sync engine's delegate nextRecordZoneChangeBatch(_:syncEngine:) for us to batch the changes together to send to iCloud.
First question: Can we guarantee that records "1" and "2" always land in the exact same batch, and are never separated?
Looking at the example code, there are two line that worry me a bit:
// (Sample project: `SyncedDatabase.swift, lines 132-133`)
let scope = context.options.scope
let changes = syncEngine.state.pendingRecordZoneChanges.filter { scope.contains($0) }
The scope could lead to one of the two records being filtered out. However, my assumption is that the scope will always be .all when the system calls it from an automatically managed schedule, and only differs when you manually specify a different value through calling syncEngine.sendChanges(_:). Is that correct?
Now back to the example. Say we successfully batched records "1" and "2" together and the changes have been sent to iCloud. Awesome!
What happens next? Other connected devices will, at some point, fetch those changes and apply them to their respective local databases.
Second question: Can we guarantee that iCloud sends the exact same batches from earlier to other devices and does not create new batches from all the changes?
I'm worried that iCloud might take all stored changes and "re-batch" them for whatever reason (efficiency, for example). Because that could cause records "1" and "2" to be separated into different batches. A second device could end up receiving "1" and, for at least some period of time, will not receive "2", which would be an "illegal" state of the data.
I'd appreciate any help or clarification on this :)
Thanks a lot!
Since a couple days ago, CloudKit database queries in my app and on the CloudKit dashboard fail with the error "request failed with http status code 500". Nothing significant changed in the app recently, and it has otherwise worked well most of the time for more than a year, although CloudKit seems to have outages somewhat frequently. My app is mostly unusable without access to the CloudKit database, so this is a critical issue.
I have also filed a Feedback report (FB13709321) on this issue.
Hi,
I started a new project selecting SwiftData as db by default.
I created my models as default.
@Model
class Trip {
var id: UUID
public private(set) var Name: String
public private(set) var Members: [Member]
public private(set) var Buys: [Buy]
public func removeBuy(indexBuyToRemove: Int) {
self.Buys.remove(at: indexBuyToRemove)
}
}
@Model
class Member: Identifiable, Equatable {
var id: UUID
public private(set) var Name: String
}
@Model
class Buy: Identifiable, Equatable {
var id: UUID
public private(set) var Author: Member
public private(set) var Ammount: Double
public private(set) var Title: String
}
I initialize my trips as this in my ContentView
@Query public var tripsList: [Trip]
And then pass this list in every other view.
I also have a ModelContext as default, passed like this in the @Main
@main
struct MainApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Member.self, Buy.self, Trip.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
.preferredColorScheme(.dark)
}
.modelContainer(sharedModelContainer)
}
}
And defining in the other views like this
@Environment(\.modelContext) var modelContext
Now. For the problem of consistency.
Whenever I add a new Trip I do this or delete (as .onDelete in the List)
public func addTrip(Trip: Trip) {
modelContext.insert(Trip)
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(tripsList[index])
}
}
}
And everything works fine.
The problem starts when I try to delete a Buy element of the Trip.Buys: [Buy].
I do like this:
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
let buyToRemove = trip.Buys[index]
trip.removeBuy(indexBuyToRemove: index)
do {
try modelContext.save()
} catch {}
}
}
}
The delete is not consistent.
What am I missing? What am I doing wrong?
Thank you for your help
Is there a way to view the data saved when using swiftdata? Even after deleting all models, the storage space taken up by the app in Settings is too large.
Porting some Core Data code that was written several years ago. It has an entity called Transaction.
This pre-dates Transaction that appeared in Animation.
So Apple is now colliding with my naming.
Looks like light weight migration isn't going to do the trick and I need to do more work for migration to work.
Checking whether there is some magical use of namespace where I could separate my entity use of Transaction. Or it's full weight migration...
Some of my users are reporting an inability to sync via CloudKit between devices. I have not seen it on any of my devices, but one user got me some console logs that are showing the following error:
<CKError 0x600000a0f840: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = EDC7B3E3-02F8-43B7-83B6-22D17EF0442A; container ID = "iCloud.cribaudo.iphemeris"; partial errors: {
C611E11F-3DC0-484C-8FC1-23473062D9D0:(com.apple.coredata.cloudkit.zone:defaultOwner) = <CKError 0x600000a04660: "Invalid Arguments" (12/2006); server message = "Cannot create or modify field 'CD_nameFirstChar' in record 'CD_Charts' in production schema"; op = D83EF1F7DD772042; uuid = EDC7B3E3-02F8-43B7-83B6-22D17EF0442A>
I do not understand this:
The field CD_nameFirstChar was added to the data model in the version 15.
Automatic Migration is enabled.
The CloudKit Console says the Private Database Container being used by my App is deployed to production.
The entity CD_Charts (I only have one) that is deployed to production shows that field as present (CD_nameFirstChar).
Why would this user be getting this error? As far as I can see they are running a version where migration to Model 15 should have been triggered at some point in the past.
If somehow something went wrong with their migration, how would I fix it?
Any thoughts / ideas are appreciated.
One thing I should add is that the migration from Model 14 to 15 was not lightweight. I did use:
@interface ModelMigration14to15 : NSEntityMigrationPolicy
-(NSString *)nameFirstChar:(NSString *)name;
@end
And I used a MapModel14to15 which used the above function to set the value of nameFirstChar. The Value Expression for that attribute is:
FUNCTION($entityPolicy,` "nameFirstChar:" , $source.name)
from the above mentioned NSEntityMigrationPolicy class.
This worked ok on all my devices and apparently on some user devices. This issues seems to effect only a small subset of my users but not all? So I am at a loss to understand why this would happen or how to fix it.
I recently discovered the new documentation for enabling CloudKit sync with SwiftData. A key step I was missing in my previous setup was this step: Initialize the CloudKit development schema.
When I run this though, I get Core Data errors in my log...
CoreData: Unsupported attribute type
I've noticed that it seems to be preventing adding fields for my model properties that are Codable structs. I've been able to add Codable structs to my SwiftData models synced with CloudKit before. But using Core Data to initialize the CloudKit schema like the documentation suggests just doesn't work. Is there some other way around this? I'm about to just give up on CloudKit sync altogether. I need this to work because I'm trying to add some new fields and populate the fields with data based on existing data during the migration, but this seems to be preventing migration completely. If I don't initialize the schema, I get different errors and the ModelContainer won't initialize at all.
What sets the SwiftData framework apart from traditional iOS data storage solutions like Core Data or Realm? Could you elaborate on SwiftData's unique features and architecture that enable developers to efficiently manage data in their Swift projects? How does SwiftData enhance the development experience by seamlessly integrating with Swift's language features and paradigms
Is it possible to deploy SwiftData to server? Or is it a good direction to consider improve SwiftData?
I have a set of cascading dependent models. I want to create a preview container that adds them all to a preview container. I have created a model container which loads a recipe of my choice in sequentialy so the instantiation works. I noticed that everything loads but only 1 RecipeStep will ever be added. No matter how I do it, only one is added (randomly).
What is the best practice for creating a swiftdata preview with dependent models? How can I put them in a struct / class for easy access? I tried making a class that initialized the whole swiftdata object however the preview crashes when using this.
Note: I know one solution is that I could make child to parent fields optional, but I don't want to do that since I need them required.
@Model
class CocktailRecipe {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var name: String
var info: String?
var menu: CocktailMenu?
@Relationship(deleteRule: .cascade, inverse: \Ingredient.recipe)
var ingredients: [Ingredient]
@Relationship(deleteRule: .cascade, inverse: \RecipeSection.recipe)
var sections: [RecipeSection]
var created_at: Date
init(name: String, info: String? = nil, menu: CocktailMenu? = nil, sections: [RecipeSection] = [], ingredients: [Ingredient] = []) {
self.name = name
self.info = info
self.menu = menu
self.sections = sections
self.ingredients = ingredients
self.created_at = Date()
self.id = UUID()
}
}
@Model
class Ingredient {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var name: String
var quantity: Float?
var units: IngredientUnitType
var type: IngredientType
var recipe: CocktailRecipe
var created_at: Date
init(name: String, quantity: Float? = nil, units: IngredientUnitType, type: IngredientType, recipe: CocktailRecipe) {
self.name = name
self.quantity = quantity
self.units = units
self.type = type
self.recipe = recipe
self.created_at = Date()
self.id = UUID()
}
}
@Model
class RecipeSection {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var title: String?
@Attribute(.unique) var index: Int
@Relationship(deleteRule: .cascade, inverse: \RecipeStep.section)
var steps: [RecipeStep]
var recipe: CocktailRecipe
var created_at: Date
init(title: String? = nil, recipe: CocktailRecipe, steps: [RecipeStep] = []) {
self.title = title
self.recipe = recipe
self.index = recipe.sections.count + 1
self.steps = steps
self.created_at = Date()
self.id = UUID()
}
}
@Model
class RecipeStep {
@Attribute(.unique) var id: UUID
@Attribute(.unique) var instruction: String
@Attribute(.unique) var index: Int
var section: RecipeSection
var created_at: Date
init(instruction: String, section: RecipeSection) {
self.instruction = instruction
self.section = section
self.index = section.steps.count + 1
self.created_at = Date()
self.id = UUID()
}
}
let cocktailPreviewContainer: ModelContainer = {
do {
let container = try ModelContainer(
for: CocktailMenu.self, CocktailRecipe.self, Ingredient.self, RecipeSection.self, RecipeStep.self, /*Bottle.self, Bar.self, */
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
let modelContext = container.mainContext
let spicyMargarita = CocktailRecipe(name: "Spicy Margarita")
modelContext.insert(spicyMargarita)
// Initialize ingredients
let spicyMargaritaIngredients = [
Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita),
Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita),
Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita),
// Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita)
]
for ingredient in spicyMargaritaIngredients {
modelContext.insert(ingredient)
}
try? modelContext.save()
// Initialize sections and steps
let preparationSection = RecipeSection(title: "title here", recipe: spicyMargarita)
modelContext.insert(preparationSection)
try? modelContext.save()
let step1 = RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection)
modelContext.insert(step1)
let step2 = RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection)
modelContext.insert(step2)
let step3 = RecipeStep(instruction: "Shake well.", section: preparationSection)
modelContext.insert(step3)
let step4 = RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection)
modelContext.insert(step4)
return container
} catch {
fatalError("Failed to create container")
}
}()
var spicyMargarita: CocktailRecipe
init() {
// Initialize spicyMargarita recipe
spicyMargarita = CocktailRecipe(name: "Spicy Margarita")
// Initialize ingredients
let tequila = Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita)
let limeJuice = Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita)
let agaveSyrup = Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita)
let jalapeno = Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita)
// Initialize sections and steps
let preparationSection = RecipeSection(recipe: spicyMargarita)
let preparationSteps = [
RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection),
RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection),
RecipeStep(instruction: "Shake well.", section: preparationSection),
RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection)
]
// WHEN THE BELOW IS COMMENTED OUT, no errors, but have many missing objects.
spicyMargarita.ingredients.append(contentsOf: [tequila, limeJuice, agaveSyrup, jalapeno])
spicyMargarita.sections.append(preparationSection)
preparationSection.steps.append(contentsOf: preparationSteps)
I am building an app that manages ScreenTime and I would like to persist the tokens of which apps are frequently limited to CoreData locally. I attempted to do so by converting to a string but was unable to find a way to initialize an ActivityCategoryToken with a string.
Is this possible? Am I going about it the wrong way?
Thanks.
I have an app that relies on CloudKit notifications for a core feature, but for about a week now the app is not receiving any CloudKit notifications. This follows a week in which I received "status 500" errors from CloudKit and my app was rendered useless. Those errors mysteriously stopped happening, but my app is still hindered by the lack of CloudKit notifications. I have not gotten any response from Apple on this, despite several attempts through various channels. It's not tenable to build apps that users rely on based on a platform that is so unreliable, and for which support is essentially nonexistent.
To any CloudKit developers reading this: Please follow up with me so that I can resolve these issues for my users.
Hello,
we are planning to migrate an app that uses iCloud documents to store some documents that the user can upload/download and modify.
In the official overview of App Transfer here, there are information related to CloudKit Containers and KVS but nothing related to iCloud Documents.
The content of iCloud Documents is accessed using FileManager.default.url(forUbiquityContainerIdentifier: containerID) where the containerID has the form iCloud.com.things.things, even if in the official documentation it is written that the identifier must be prefixed with the Team ID.
With this ID the storage works properly and we never experienced problems.
Do you know if migrating an app with this functionality can be problematic? Do you know if the Team ID is somehow used even if not explicitly passed in the call to the function?
Thank you and have a nice day!
Previously iCloud Drive worked fine on my iPhone (15 Pro), but within the last couple of months it seems to have died. It continues to work fine on other connected devices (iPad, MBP etc), but will not work on iPhone.
This issue seemed to begin roughly around the early 17.4 betas, but was also present in the public release and has continued on to the current 17.5 betas.
I initially noticed WhatsApp couldn't back up to iCloud despite all the options being turned on. I assumed this was a WhatsApp issue. But I've recently noticed that Castro hangs on every single load and then crashes. I know that Castro does an initial call to iCloud to check back-ups etc so I went to have a look at iCloud Drive itself on my device - every single time I open Files, iCloud Drive takes 10-15 minutes to load/show anything. So it seems that iCloud Drive is not "holding" any information/content and is then taking an age to load, which is causing these other apps to time-out and crash.
Turning off iCloud Drive on the device (a 35 minute waiting process) stops the issues and the apps work fine (aside from now not being able to back-up to iCloud as it's off), but resetting, allowing to re-sync again, does not resolve the issue on the device at all, and if it's turned back on, the apps begin to fail again, and even after a full re-sync it takes 10-15 minutes to load every time.
To note; my connection is not an issue, and I have more than enough space on-device to cache/store stuff that's required.
Any thoughts on what could be causing the issue and how to resolve?
Dear all,
I'm quite new to SwiftUI.
I have a view where I'd like to open a sheet to edit data in a List. Here below the code of the view:
import SwiftUI
import SwiftData
struct SettingsView: View {
@Query(sort: \Stagione.idStagione) private var usoStagione: [Stagione]
@Environment(\.modelContext) private var context
@State private var stagione = String(Calendar.current.component(.year, from: Date()))
@State private var miaSquadra = ""
@State private var categoria = ""
@State private var selStagione = Set<Stagione>()
@State private var modificaStagione = false
var body: some View {
NavigationStack {
GroupBox("Stagione") {
Form {
TextField("Stagione:", text: $stagione)
.frame(width: 150)
TextField("Categoria:", text: $categoria)
.frame(width: 400)
TextField("Mia squadra:", text: $miaSquadra)
.frame(width: 400)
Button("Salva") {
let nuovaStagione = Stagione(idStagione: stagione, categoriaStagione: categoria, miaSquadra: miaSquadra)
context.insert(nuovaStagione)
miaSquadra = ""
categoria = ""
stagione = String(Calendar.current.component(.year, from: Date()))
}
.frame(maxWidth: .infinity, alignment: .trailing)
.buttonStyle(.borderedProminent)
.disabled(categoria.isEmpty || miaSquadra.isEmpty)
}
List(selection: $selStagione) {
ForEach(usoStagione, id: \.self) { stag in
VStack(alignment: .leading) {
Text("\(stag.idStagione)").font(.title2)
Text("\(stag.miaSquadra)").foregroundStyle(.secondary)
Text("\(stag.categoriaStagione)").foregroundStyle(.secondary)
}
}
.contextMenu() {
Button(action: {
selStagione.forEach(context.delete)
}) {
Text("Cancella")
}
Button(action: {
self.modificaStagione = true
}) {
Text("Modifica")
}
}
}
.sheet(isPresented: $modificaStagione) {
ModificaStagione(stagione: Stagione)
}
.listStyle(.plain)
.textFieldStyle(.roundedBorder)
.padding()
}
}
.padding()
.textFieldStyle(.roundedBorder)
.navigationTitle("Impostazioni")
GroupBox("Squadre") {
}
}
}
#Preview {
SettingsView()
.environmentObject(NavigationStateManager())
.modelContainer(for: Stagione.self, inMemory: true)
}
While here below the code of the view ModificaStagione:
import SwiftUI
struct ModificaStagione: View {
@Environment(\.dismiss) private var dismiss
let stagione: Stagione
@State private var idStagione = ""
@State private var categoria = ""
@State private var miaSquadra = ""
@State private var vistaPrecedente = true
var body: some View {
VStack (alignment: .leading) {
GroupBox {
LabeledContent {
TextField("", text: $categoria)
.frame(width: 400)
} label: {
Text("Categoria:")
}
LabeledContent {
TextField("", text: $miaSquadra)
.frame(width: 400)
} label: {
Text("Mia squadra:")
}
if modifica {
Button("Aggiorna dati") {
stagione.idStagione = idStagione
stagione.categoriaStagione = categoria
stagione.miaSquadra = miaSquadra
dismiss()
}
.buttonStyle(.borderedProminent)
}
}
.padding()
.textFieldStyle(.roundedBorder)
.navigationTitle("Modifica dati stagione")
}
.onAppear {
idStagione = stagione.idStagione
categoria = stagione.categoriaStagione
miaSquadra = stagione.miaSquadra
}
}
var modifica: Bool {
categoria != stagione.categoriaStagione
|| miaSquadra != stagione.miaSquadra
}
}
In the "Setting" view I receive an error message when I call the view "Modifica Stagione "saying that "Cannot convert value of type 'Stagione.Type' to expected argument type 'Stagione'".
What am I doing wrong?
Thanks in advance,
A.
Hey Everyone,
I am working on this project and it has to be done really soon.
I have 30 TextFields and I need it to be saved to the whole app so If I had 1 phone inputting it, it would sync to another one with the same text value in it.
So say I put "Done" in one TextField on Phone 1 then it'll save and update on Phone 2.
Please get back to me when someone can.
I have been developing in Xcode for about 7 months now and I am just running into it right now!
Thanks so much
I used Query(filter:sortBy:) and show them in the ListView.
When I change the property of the model, because I fetched filtered and sorted array, the model immediately reflect the change and find its position.
What I want is at initializing it fetches filtered and sorted array. And when I change the property nothing happens. But when I tap on refresh button, then the array should change.
For example in ToDoList app, the array consists of not done works. when I tap done, it should stay until I refresh.
Is it possible?
We currently have a shoebox-based architecture but want to transition to a document-based architecture, so UIManagedDocument seems like an obvious choice. However, the UIManagedDocument API seems outdated given the relatively newer NSPersistentContainer API. Also, it’s not clear if UIManagedDocument’s managedObjectContext can be used on the main thread or not.
Ideally, I would like to see a persistentContainer property added to UIManagedDocument which could then be used to obtain the view context or a background managed object context.
Does anyone have any suggestions on the latest best practices for document-based architectures using CoreData? I’m more interested in Swift implementations, but knowing best practices for SwiftUI and SwiftData would be helpful too.
Hello. See the code below.
struct ContentView: View {
var body: some View {
TabView {
VehicleTab()
.tabItem({ Label("Vehicles", systemImage: "car.fill")})
.modelContainer(for: Vehicle.self)
TransactionsTab()
.tabItem { Label("Transactions", systemImage: "dollarsign") }
.modelContainer(for: Transaction.self)
}
}
}
Using the .modelContainer() in this way seems to be causing some issue. I was under the assumption that this would just create a container for each view. I get the error below in this configuration. If I comment out either one of the .modelContainer() modifiers, it works fine.
Query encountered an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “default.store” couldn’t be opened."
Are you not able to do what I'm doing? Is there a way to have two separate containers?