I'm working on a SwiftUI app generating data using a standard CoreData data model and sync it with iCloud using NSPersistentCloudKitContainer. In this data model one parent is referencing on many children (e.g. > 2000 of children A and B). Each child A is also referencing onto one child B and vice versa:
Parent ----> Child A;
Parent ----> Child B;
Child A <---> Child B
The problem I am facing is, depending on the last time an CloudKit sync has been performed, the sync process takes hours to complete (where in the mean time the app might be sent to the background by the system or by the user and the sync is stopped).
Is there a way to efficiently sync these larger datasets?
Additionally I would like to pause the iCloud sync for specific occasions e.g. when performing continuous tasks using "Background Modes" and the app would be killed due to CPU pressure of iCloud sync.
Is there a way to customize the syncing behavior of NSPersistentCloudKitContainer like e.g. CKOperation or by scheduled execution of iCloud sync via "Background Tasks" or "Background Fetch"?
Thank you for you help.
Post
Replies
Boosts
Views
Activity
Hi everyone!
I'm currently struggling with dynamically filtering data in a SwiftUi List view. In the following example, I created some example data and stored them within "TestArray". These data is dynamically filtered and grouped by the starting letter.
The data of the "Testclass" objects can be changed in "EditDetails" view. Unfortunately, when changing the name (as it is the relevant property for filtering here), when closing the modal, the user does not return to DetailView but will break the view hierarchy and end up in the ContentView. I assume the issue is the update within ContentView, which is recreating the DetailView stack.
Is it possible to ensure the return to view, where the modal has been opened from (DetailView)?
Here is some code if you would like to reproduce the issue:
import Foundation
import SwiftUI
import Combine
struct ContentView: View {
@StateObject var objects = TestArray()
var body: some View {
NavigationView{
List {
ForEach(objects.objectList.compactMap({$0.name.first}).unique(), id: \.self) { obj in
Section(header: Text(String(obj))) {
ForEach(objects.objectList.filter({$0.name.first == obj}), id: \.self) { groupObj in
NavigationLink(destination: Detailview(testclass: groupObj)) {
Text("\(groupObj.name)")
}
}
}
}
}
}
}
}
struct Detailview: View {
@ObservedObject var testclass: Testclass
@State private var showingEdit: Bool = false
var body: some View {
VStack {
Text("Hello, \(testclass.name)!")
Text("\(testclass.date)!")
}
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button(action: {
self.showingEdit.toggle()
}) {
Image(systemName: "square.and.pencil")
}
}
}
.sheet(isPresented: $showingEdit) {
EditDetails(testclass: testclass, showEdit: $showingEdit)
}
}
}
struct EditDetails: View {
@ObservedObject var testclass: Testclass
@Binding var showEdit: Bool
@State private var name: String
@State private var date: Date = Date()
init(testclass: Testclass, showEdit: Binding<Bool>) {
self.testclass = testclass
_name = State(initialValue: testclass.name)
_date = State(initialValue: testclass.date)
_showEdit = Binding(projectedValue: showEdit)
}
var body: some View {
NavigationView{
List {
TextField("Name", text: $name)
.onChange(of: name, perform: { newValue in
self.testclass.name = newValue
})
DatePicker(selection: $date) {
Text("Date")
}
.onChange(of: date, perform: { newValue in
self.testclass.date = newValue
})
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
testclass.objectWillChange.send()
showEdit.toggle()
}) {
Image(systemName: "xmark")
}
}
}
}
}
}
extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
var seen: Set<Iterator.Element> = []
return filter { seen.insert($0).inserted }
}
}
class Testclass: NSObject, ObservableObject {
@Published var name: String
@Published var date: Date
init(name: String, date: Date = Date()) {
self.name = name
self.date = date
super.init()
}
}
class TestArray: NSObject, ObservableObject {
@Published var objectList: [Testclass]
private var cancellables = Set<AnyCancellable>()
override init() {
self.objectList = [
Testclass(name: "A1"),
Testclass(name: "B1"),
Testclass(name: "Z2"),
Testclass(name: "C1"),
Testclass(name: "D1"),
Testclass(name: "D2"),
Testclass(name: "A2"),
Testclass(name: "Z1")
]
super.init()
objectList.forEach { object in
object.objectWillChange
.receive(on: DispatchQueue.main) // Optional
.sink(receiveValue: { [weak self] _ in
self?.objectWillChange.send()
print("changed value \(object.name)")
})
.store(in: &cancellables)
}
}
}
Hi all,
I'm just switching my app to use a separate synchronized and local CoreData store.
Normally, for setting my SQLite as in-memory for utilization in UnitTests, I use the common setup of setting the URL to "/dev/null/":
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null/")
Anyone an idea, how to use this approach when using multiple stores, as I can't link both persistentStoreDescriptions to the same URL?
Many thanks for your help.
Folox
Hi Folks,
starting with iOS18 and using Xcode16, accessing fetchedProperties results in an error. I identified the issue to occur as soon as the initialization of a fetched property with external binary data storage starts.
Console output during debugging:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This expression has evaluation disabled'
*** First throw call stack:
[...]
libc++abi: terminating due to uncaught exception of type NSException
Console output when trying to "print" the item via the contact menu of the debugger:
Printing description of variable:
error: error: Execution was interrupted, reason: internal ObjC exception breakpoint(-6)..
The process has been returned to the state before expression evaluation.
Message from debugger: killed
The identical code works with iOS before iOS 18 (same for iPadOS 18).
Does anyone observed a similar issue and figured out a solution already?
Cheers,
folox