Hi everyone,
Im trying to set up CloudKit for my Unreal Engine 5.4 project but seem to be hitting some roadblocks on how to set up the Record Types.
From my understanding I need to set up a "file" record type with a "contents" asset field - but even with this it doesn't seem to work :(
Any unreal engine devs with some experience on this who could help me out?
Thanks!
                    
                  
                iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
  
    
    Selecting any option will automatically load the page
  
  
  
  
    
  
  
            Post
Replies
Boosts
Views
Activity
                    
                      I'm trying to build a custom FetchRequest that I can use outside a View. I've built the following ObservableFetchRequest class based on this article: https://augmentedcode.io/2023/04/03/nsfetchedresultscontroller-wrapper-for-swiftui-view-models
@Observable @MainActor class ObservableFetchRequest<Result: Storable>: NSObject, @preconcurrency NSFetchedResultsControllerDelegate {
    
    private let controller: NSFetchedResultsController<Result.E>
    private var results: [Result] = []
    
    init(context: NSManagedObjectContext = .default, predicate: NSPredicate? = Result.E.defaultPredicate(), sortDescriptors: [NSSortDescriptor] = Result.E.sortDescripors) {
        
        guard let request = Result.E.fetchRequest() as? NSFetchRequest<Result.E> else {
            fatalError("Failed to create fetch request for \(Result.self)")
        }
        
        request.predicate = predicate
        request.sortDescriptors = sortDescriptors
        
        controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        
        super.init()
        
        controller.delegate = self
        
        fetch()
    }
    
    private func fetch() {
        do {
            try controller.performFetch()
            refresh()
        }
        
        catch {
            fatalError("Failed to fetch results for \(Result.self)")
        }
    }
    
    private func refresh() {
        results = controller.fetchedObjects?.map { Result($0) } ?? []
    }
    
    var predicate: NSPredicate? {
        get {
            controller.fetchRequest.predicate
        }
        set {
            controller.fetchRequest.predicate = newValue
            fetch()
        }
    }
    
    var sortDescriptors: [NSSortDescriptor] {
        get {
            controller.fetchRequest.sortDescriptors ?? []
        }
        set {
            controller.fetchRequest.sortDescriptors = newValue.isEmpty ? nil : newValue
            fetch()
        }
    }
    
    internal func controllerDidChangeContent(_ controller: NSFetchedResultsController<any NSFetchRequestResult>) {
        refresh()
    }
}
Till this point, everything works fine.
Then, I conformed my class to RandomAccessCollection, so I could use in a ForEach loop without having to access the results property.
extension ObservableFetchRequest: @preconcurrency RandomAccessCollection, @preconcurrency MutableCollection {
    
    subscript(position: Index) -> Result {
        get {
            results[position]
        }
        
        set {
            results[position] = newValue
        }
    }
    
    public var endIndex: Index { results.endIndex }
    public var indices: Indices { results.indices }
    public var startIndex: Index { results.startIndex }
    
    public func distance(from start: Index, to end: Index) -> Int {
        results.distance(from: start, to: end)
    }
    
    public func index(_ i: Index, offsetBy distance: Int) -> Index {
        results.index(i, offsetBy: distance)
    }
    
    public func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Index) -> Index? {
        results.index(i, offsetBy: distance, limitedBy: limit)
    }
    
    public func index(after i: Index) -> Index {
        results.index(after: i)
    }
    
    public func index(before i: Index) -> Index {
        results.index(before: i)
    }
    public typealias Element = Result
    public typealias Index = Int
}
The issue is, when I update the ObservableFetchRequest predicate while searching, it causes a Index out of range error in the Collection subscript because the ForEach loop (or a List loop) access a old version of the array when the item property is optional.
List(request, selection: $selection) { item in
                VStack(alignment: .leading) {
                    Text(item.content)
                    if let information = item.information { // here's the issue, if I leave this out, everything works
                        Text(information)
                            .font(.callout)
                            .foregroundStyle(.secondary)
                    }
                }
                .tag(item.id)
                .contextMenu {
                    if Item.self is Client.Type {
                        Button("Editar") {
                            openWindow(ClientView(client: item as! Client), id: item.id!)
                        }
                    }
                }
            }
Is it some RandomAccessCollection issue or a SwiftUI bug?
                    
                  
                
                    
                      Document based SwiftData apps do not autosave changes to the ModelContext at all. This issue has been around since the first release of this SwiftData feature.
In fact, the Apple WWDC sample project (https://developer.apple.com/documentation/swiftui/building-a-document-based-app-using-swiftdata) does not persist any data in its current state, unless one inserts modelContext.save() calls after every data change.
I have reported this under the feedback ID FB16503154, as it seemed to me that there is no feedback report about the fundamental issue yet.
Other posts related to this problem:
https://forums.developer.apple.com/forums/thread/757172
https://forums.developer.apple.com/forums/thread/768906
https://developer.apple.com/forums/thread/764189
                    
                  
                
                    
                      Let's say I have a CloudKit database schema where I have records of type Author that are referenced by multiple records of type Article.
I want to delete an Author record if no Article is referencing it. Now consider the following conflict:
device A deleted the last Article referencing Author #42
device B uploads a new Article referencing Author #42 at the same time
The result should be that Author #42 is not deleted after both operations are finished. But both device don't know from each other changes. So either device B could miss that device A deleted the author. Or device A could have missed that a new Article was uploaded and therefore the Author #42 was deleted right after the upload of device B.
I though about using a reference count first. But this won't work if the ref count is part of the Author record. This is because deletions do not use the changeTag to detect lost updates: If device A found a reference count 0 and decides to delete the Author, it might miss that device B incremented the count meanwhile.
I currently see two alternatives:
Using a second record that outlives the Author to keep the reference count and using an atomic operation to update and delete it. So if the update fails, the delete would fail either.
Always adding a new child record to the Author whenever a reference is made. We could call it ReferenceToken. Since child records may not become dangling, CloudKit would stop a deletion, if a new ReferenceToken sets the parent reference to the Author.
Are there any better ways doing this?
                    
                  
                
                    
                      While reading the developer documentation article Adopting SwiftData for a Core Data App, one particular line piqued my interest.
For apps that evolve from a version that doesn’t have any app group container to a version that has one, SwiftData copies the existing store to the app group container.
Given how troublesome it has been to migrate the Core Data persistent store to an app group container, I decided to try this out myself. I created an Xcode project using the default Core Data template. I then added a few Item objects with timestamps. There, I had what we would consider a regular Core Data app.
I then created a widget extension for this app since this is one of the most common uses for adopting an app group in an Xcode project. After that, I linked the main target with the widget extension using an app group. In the widget extension, I tried to fetch the Item objects. I utilized the SwiftData code in the sample project associated with the article above.
struct Provider: TimelineProvider {
    private let modelContainer: ModelContainer
    
    init() {
        let appGroupContainerID = "group.com.genebogdanovich.CoreDataSwiftDataAppGroup"
        guard let appGroupContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupContainerID) else {
            fatalError("Shared file container could not be created.")
        }
        let url = appGroupContainer.appendingPathComponent("CoreDataSwiftDataAppGroup.sqlite")
        print("\(url)")
        do {
            modelContainer = try ModelContainer(for: Item.self, configurations: ModelConfiguration(url: url))
        } catch {
            fatalError("Failed to create the model container: \(error)")
        }
    }
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
    
    Task { @MainActor in
        let fetchDescriptor = FetchDescriptor<Item>()
        
        let items: [Item] = try! modelContainer.mainContext.fetch(fetchDescriptor)
        
        print(items)
        
        let entry = SimpleEntry(date: .now, emoji: "😀", count: items.count)
        
        let timeline = Timeline(entries: [entry], policy: .never)
        completion(timeline)
    }
}
The fetch yielded no results. However, as I explored the app group directory in the file system, I found a .sqlite file. That is interesting because SwiftData creates .store files by default. So, I am guessing that SwiftData did copy something. Or the ModelContainer initializer just created another empty SQLite file since the fetch returned zero results.
I would highly appreciate someone elaborating on that quote from the documentation.
                    
                  
                
                    
                      Greetings i have an app that uses three different SwiftData models and i want to know what is the best way to use the them accross the app. I though a centralized behaviour and i want to know if it a correct approach.First let's suppose that the first view of the app will load the three models using the @Enviroment that work with @Observation. Then to other views that add data to the swiftModels again with the @Environment. Another View that will use the swiftData models with graph and datas for average and min and max.Is this a corrent way? or i should use @Query in every view that i want and ModelContext when i add the data.
@Observable
class CentralizedDataModels {
var firstDataModel: [FirstDataModel] = []
var secondDataModel: [SecondDataModel] = []
var thirdDataModel: [ThirdDataModel] = []
let context: ModelContext
init(context:ModelContext) {
self.context = context
}
}
                    
                  
                
                    
                      Hi,
I'm developing an app for iOS and MacOS with SwiftData and CloudKit syncing. I had sync working very well with a set of models. This schema was also pushed to CloudKit production.
Last week I added several models, and several relationship properties linking my existing models to newly added models. The schema updated just fine and everything worked.
Then things went sideways: earlier this week I decided I wanted to rename a property on one of my new models. So I renamed the property, removed the application support folder for my local debug app (on Mac OS), removed the app from the iOS Simulator (to clear its local database), and finally reset my CloudKit container to its Production schema. Basically, I tried to go back to the same state I had as when I first added the new models.
However, this time things don't go so smoothly, even after starting the app several times, rebooting my machine, turning iCloud on and off in Xcode and MacOS and iOS. When I look in CloudKit console, I see only my old models there: none of the new ones are added.
I'd love some pointers on how I can best debug this issue, as I feel completely stuck.
On MacOS
I have very little
mac-logs.txt
to go on. Since the logs are a bit lengthy I've added them as an attachment. I get a few warnings, but it is unclear what they are warning me about.
One thing that does stand out is that I am running the CloudKit in Development mode here. However, the logs do state accountPartition=Prod . And when I query CKContainer.default() for the container environment, the response is sandbox, which matches Development!
On iOS
The logs show a few errors, but I cannot make sense of them.
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1240): <NSCloudKitMirroringDelegate: 0x600003d09860>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x103325c90> (URL: file:///Users/bastiaan/Library/Developer/CoreSimulator/Devices/BF847CE5-A3E2-4B4C-8CD5-616B75B29AFE/data/Containers/Data/Application/0A916F67-B9B2-457B-8FA7-8C42819EA9AA/Library/Application%20Support/default.store)
<CKError 0x600000c433f0: "Partial Failure" (2/1011); "Failed to modify some record zones"; partial errors: {
	com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x600000c956b0: "Internal Error" (1/5005); "Couldn't create new PCS blob for zone <CKRecordZoneID: 0x600000c475d0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>">
}>
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate recoverFromError:](2310): <NSCloudKitMirroringDelegate: 0x600003d09860> - Attempting recovery from error: <CKError 0x600000c433f0: "Partial Failure" (2/1011); "Failed to modify some record zones"; partial errors: {
	com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x600000c956b0: "Internal Error" (1/5005); "Couldn't create new PCS blob for zone <CKRecordZoneID: 0x600000c475d0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>">
}>
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _recoverFromPartialError:forStore:inMonitor:]_block_invoke(2773): <NSCloudKitMirroringDelegate: 0x600003d09860>: Found unknown error as part of a partial failure: <CKError 0x600000c956b0: "Internal Error" (1/5005); "Couldn't create new PCS blob for zone <CKRecordZoneID: 0x600000c475d0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>">
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _recoverFromPartialError:forStore:inMonitor:](2820): <NSCloudKitMirroringDelegate: 0x600003d09860>: Error recovery failed because the following fatal errors were found: {
    "<CKRecordZoneID: 0x600000c8fd50; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>" = "<CKError 0x600000c956b0: \"Internal Error\" (1/5005); \"Couldn't create new PCS blob for zone <CKRecordZoneID: 0x600000c475d0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>\">";
}
And in CloudKit logs I see:
06/11/2024, 9:09:59 UTC 738513AC-9326-42DE-B4E2-DA51F6462943 iOS;18.1 ZoneFetch EphemeralGroup
{
"time":"06/11/2024, 9:09:59 UTC"
"database":"PRIVATE"
"zone":"com.apple.coredata.cloudkit.zone"
"userId":"_0d9445f850459ec351330ca0fde4134f"
"operationId":"611BA98C9B10D3F2"
"operationGroupName":"EphemeralGroup"
"operationType":"ZoneFetch"
"platform":"iPhone"
"clientOS":"iOS;18.1"
"overallStatus":"USER_ERROR"
"error":"ZONE_NOT_FOUND"
"requestId":"738513AC-9326-42DE-B4E2-DA51F6462943"
"executionTimeMs":"53"
"interfaceType":"NATIVE"
}
Any pointers are greatly appreciated!
Bastiaan
                    
                  
                
                    
                      I'm trying to use the new (in tvOS 26) video streaming service automatic login API from the VideoSubscriberAccount framework:
https://developer.apple.com/documentation/videosubscriberaccount/vsuseraccountmanager/autosignintoken-swift.property
It seems that this API requires an entitlement. This document suggests that the com.apple.smoot.subscriptionservice entitlement is required.
https://developer.apple.com/documentation/videosubscriberaccount/signing-people-in-to-media-apps-automatically
However, it seems more likely that com.apple.developer.video-subscriber-single-sign-on is the correct entitlement.
https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.video-subscriber-single-sign-on
Which is the correct entitlement and how do I obtain it?
I don't want to fully comply with the video partner program.
https://developer.apple.com/programs/video-partner/
I just want to use this one new automatic login feature.
                    
                  
                
                    
                      I have developed an podcast app, where subscriped podcast & episodes synched with iCloud.
So its working fine with iOS & iPad with latest os version, but iCloud not synching in iPod with version 15.
Please help me to fix this.
Thanks
Devendra K.
                    
                  
                
                    
                      Hello. I am re-writing our way of storing data into Core Data in our app, so it can be done concurrently.
The solution I opted for is to have a singleton actor that takes an API model, and maps it to a Core Data object and saves it.
For example, to store an API order model, I have something like this:
func store(
  order apiOrder: APIOrder,
  currentContext: NSManagedObjectContext?
) -> NSManagedObjectID? {
  let context = currentContext ?? self.persistentContainer.newBackgroundContext()
  // …
}
In the arguments, there is a context you can pass, in case you need to create additional models and relate them to each other. I am not sure this is how you're supposed to do it, but it seemed to work.
From what I've understood of Core Data and using multiple contexts, the appropriate way use them is with context.perform or context.performAndWait.
However, since my storage helper is an actor, @globalActor actor Storage2 { … }, my storage's methods are actor-isolated.
This gives me warnings / errors in Swift 6 when I try to pass the context for to another of my actor's methods.
let context = …
return context.performAndWait {
  // …
  if let apiBooking = apiOrder.booking {
    self.store(booking: apiBooking, context: context)
    /* causes warning:
     Sending 'context' risks causing data races; this is an error in the Swift 6 language mode
        'self'-isolated 'context' is captured by a actor-isolated closure. actor-isolated uses in closure may race against later nonisolated uses
        Access can happen concurrently
    */
  }
  // …
}
From what I understand this is because my methods are actor-isolated, but the closure of performAndWait does not execute in a thread safe environment.
With all this, what are my options? I've extracted the store(departure:context:) into its own method to avoid duplicated code, but since I can't call it from within performAndWait I am not sure what to do.
Can I ditch the performAndWait? Removing that makes the warning "go away", but I don't feel confident enough with Core Data to know the answer.
I would love to get any feedback on this, hoping to learn!
                    
                  
                
                    
                      We're in the process of migrating our app to the Swift 6 language mode. I have hit a road block that I cannot wrap my head around, and it concerns Core Data and how we work with NSManagedObject instances.
Greatly simplied, our Core Data stack looks like this:
class CoreDataStack {
    private let persistentContainer: NSPersistentContainer
    var viewContext: NSManagedObjectContext { persistentContainer.viewContext }
}
For accessing the database, we provide Controller classes such as e.g.
class PersonController {
    private let coreDataStack: CoreDataStack
    func fetchPerson(byName name: String) async throws -> Person? {
        try await coreDataStack.viewContext.perform {
            let fetchRequest = NSFetchRequest<Person>()
            fetchRequest.predicate = NSPredicate(format: "name == %@", name)
            return try fetchRequest.execute().first
        }
    }
}
Our view controllers use such controllers to fetch objects and populate their UI with it:
class MyViewController: UIViewController {
    private let chatController: PersonController
    private let ageLabel: UILabel
    func populateAgeLabel(name: String) {
        Task {
            let person = try? await chatController.fetchPerson(byName: name)
            ageLabel.text = "\(person?.age ?? 0)"
        }
    }
}
This works very well, and there are no concurrency problems since the managed objects are fetched from the view context and accessed only in the main thread.
When turning on Swift 6 language mode, however, the compiler complains about the line calling the controller method:
Non-sendable result type 'Person?' cannot be sent from nonisolated context in call to instance method 'fetchPerson(byName:)'
Ok, fair enough, NSManagedObject is not Sendable. No biggie, just add @MainActor to the controller method, so it can be called from view controllers which are also main actor. However, now the compiler shows the same error at the controller method calling viewContext.perform:
Non-sendable result type 'Person?' cannot be sent from nonisolated context in call to instance method 'perform(schedule:_:)'
And now I'm stumped. Does this mean NSManageObject instances cannot even be returned from calls to NSManagedObjectContext.perform? Ever? Even though in this case, @MainActor matches the context's actor isolation (since it's the view context)?
Of course, in this simple example the controller method could just return the age directly, and more complex scenarios could return Sendable data structures that are instantiated inside the perform closure. But is that really the only legal solution? That would mean a huge refactoring challenge for our app, since we use NSManageObject instances fetched from the view context everywhere. That's what the view context is for, right?
tl;dr: is it possible to return NSManagedObject instances fetched from the view context with Swift 6 strict concurrency enabled, and if so how?
                    
                  
                
                    
                      SwiftData crashes 100% when fetching history of a model that contains an optional codable property that's updated:
SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test.
Would really appreciate some help or even a workaround.
Code:
import Foundation
import SwiftData
import Testing
struct VaultsSwiftDataKnownIssuesTests {
    @Test
    func testCodableCrashInHistoryFetch() async throws {
        let container = try ModelContainer(
            for: CrashModel.self,
            configurations: .init(
                isStoredInMemoryOnly: true
            )
        )
        let context = ModelContext(container)
        try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
        // 1: insert a new value and save
        let model = CrashModel()
        model.someCodableID = SomeCodableID(someID: "testid1")
        context.insert(model)
        try context.save()
        // 2: check history it's fine.
        try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
        // 3: update the inserted value before then save
        model.someCodableID = SomeCodableID(someID: "testid2")
        try context.save()
        // The next check will always crash on fetchHistory with this error:
        /*
         SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test.
         */
        try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
    }
}
@Model final class CrashModel {
    // optional codable crashes.
    var someCodableID: SomeCodableID?
    // these actually work:
    //var someCodableID: SomeCodableID
    //var someCodableID: [SomeCodableID]
    init() {}
}
public struct SomeCodableID: Codable {
    public let someID: String
}
final class SimpleHistoryChecker {
    static func hasLocalHistoryChanges(context: ModelContext) throws {
        let descriptor = HistoryDescriptor<DefaultHistoryTransaction>()
        let history = try context.fetchHistory(descriptor)
        guard let last = history.last else {
            return
        }
        print(last)
    }
}
                    
                  
                
                    
                      Hi, I have been looking into Core Data crashes happening when the app is in background and fault is fired due to some processing happening within the app. The stack looks like this where the line 5 just accesses a property of the NSManagedObject's subclass.
Unfortunately I don't see any additional information about the exception itself. Therefore, I was wondering if anyone could shed some light on which exception the NSFaultHandler.m:395 is triggering and why.
Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread:  10
Last Exception Backtrace:
0   CoreFoundation                	0x1d15b8e38 __exceptionPreprocess + 164 (NSException.m:202)
1   libobjc.A.dylib               	0x1ca7478d8 objc_exception_throw + 60 (objc-exception.mm:356)
2   CoreData                      	0x1d8dda27c _PFFaultHandlerLookupRow + 2508 (NSFaultHandler.m:395)
3   CoreData                      	0x1d8e024e0 _PF_FulfillDeferredFault + 200 (NSFaultHandler.m:915)
4   CoreData                      	0x1d8eb8f1c _sharedIMPL_pvfk_core + 168 (NSManagedObject_Accessors.m:1198)
5   MyApp                       	0x103641928 closure #8 in static ChatChannel.create(fromDTO:depth:) + 304 (ChannelDTO.swift:531)
At first I was thinking if this could be a case of accessing a deleted object while the context is still referencing it, but does not look like it. At least I can't reproduce it (tried deleting objects using a separate context and even  with container but no crash happens).
Happy to learn about different cases what could trigger exception with this stack.
Notes:
Contexts I use are all created with newBackgroundContext method.
                    
                  
                
                    
                      Testing Environment: iOS 18.4.1 / macOS 15.4.1
I am working on an iOS project that aims to utilize the user's iCloud Drive documents directory to save a specific directory-based file structure. Essentially, the app would create a root directory where the user chooses in iCloud Drive, then it would populate user generated files in various levels of nested directories.
I have been attempting to use NSMetadataQuery with various predicates and search scopes but haven't been able to get it to directly monitor changes to files or directories that are not in the root directory.
Instead, it only monitors files or directories in the root directory, and any changes in a subdirectory are considered an update to the direct children of the root directory.
Example
iCloud Drive Documents (Not app's ubiquity container)
User Created Root Directory (Being monitored)
File A
Directory A
File B
An insertion or deletion within Directory A would only return a notification with userInfo containing data for NSMetadataQueryUpdateChangedItemsKey relating to Directory A, and not the file or directory itself that was inserted or deleted. (Query results array also only contain the direct children.)
I have tried all combinations of these search scopes and predicates with no luck:
query.searchScopes = [
  rootDirectoryURL,
  NSMetadataQueryUbiquitousDocumentsScope,
  NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope,
]
NSPredicate(value: true)
NSPredicate(format: "%K LIKE '*.md'", NSMetadataItemFSNameKey)
NSPredicate(format: "%K BEGINSWITH %@", NSMetadataItemPathKey, url.path(percentEncoded: false))
I do see these warnings in the console upon starting my query:
[CRIT] UNREACHABLE: failed to get container URL for com.apple.CloudDocs
[ERROR] couldn't fetch remote operation IDs: NSError: Cocoa 257 "The file couldn’t be opened because you don’t have permission to view it."
"Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)""
But I am not sure what to make of that, since it does act normally for finding updates in the root directory.
Hopefully this isn't a limitation of the API, as the only alternative I could think of would be to have multiple queries running for each nested directory that I needed updates for.
                    
                  
                
              
                
              
              
                
                Topic:
                  
	
		App & System Services
  	
                
                
                SubTopic:
                  
                    
	
		iCloud & Data
		
  	
                  
                
              
              
                Tags:
              
              
  
  
    
      
      
      
        
          
            Files and Storage
          
        
        
      
      
    
      
      
      
        
          
            iCloud Drive
          
        
        
      
      
    
      
      
      
        
          
            Foundation
          
        
        
      
      
    
  
  
              
                
                
              
            
          
                    
                      Hi all,
I recently discovered that I forgot to deploy my CloudKit schema changes from development to production - an oversight that unfortunately went unnoticed for 2.5 months.
As a result, any data created during that time was never synced to iCloud and remains only in the local CoreData store. Once I pushed the schema to production, CloudKit resumed syncing new changes as expected.
However, this leaves me with a gap: there's now a significant amount of data that would be lost if users delete or reinstall the app.
Before I attempt to implement a manual backup or migration strategy, I was wondering:
Does NSPersistentCloudKitContainer keep track of local changes that couldn't be synced doe to the missing schema and automatically reattempt syncing them now that the schema is live?
If not, what would be the best approach to ensure this "orphaned" data gets saved to CloudKit retroactively.
Thanks in advance for any guidance or suggestions.
                    
                  
                
                    
                      In a document based SwiftData app for macOS, how do you go about opening a (modal) child window connected to the ModelContainer of the currently open document?
Using .sheet() does not really result in a good UX, as the appearing view lacks the standard window toolbar.
Using a separate WindowGroup with an argument would achieve the desired UX. However, as WindowGroup arguments need to be Hashable and Codable, there is no way to pass a ModelContainer or a ModelContext there:
        WindowGroup(id: "myWindowGroup", for: MyWindowGroupArguments.self) { $args in
                ViewThatOpensInAWindow(args: args)
        }
Is there any other way?
                    
                  
                
                    
                      struct ModelContainerSetup {
static let shared = ModelContainerSetup()
private static let containerIdentifier = "iCloud.Journal"
func setupModelContainer() -> ModelContainer {
    let schema = Schema([User.self])
    let modelConfiguration = ModelConfiguration(
        schema: schema,
        isStoredInMemoryOnly: false,
        cloudKitDatabase: .private(Self.containerIdentifier)
    )
   
    do {
        return try ModelContainer(for: schema, configurations: [modelConfiguration])
    } catch {
        fatalError("Could not create ModelContainer: \(error)")
    }
}
**Expected Behavior:
**
When CloudKit storage is full, the app should continue functioning with local storage
Data should persist locally even if cloud sync fails
Sync should resume when storage becomes available
**Actual Behavior:
**
ModelContainer initialization fails completely
Local data also stops getting saved
**Environment:
**
iOS 17.0+
SwiftData
Private CloudKit database
Ideal Behaviour:
When iCloud fails, the data should still be saved locally. I do not want to have two different containers so that I can maintain data consistency.
                    
                  
                
                    
                      I have a SwiftData model where I need to customize behavior based on the value of a property (connectorType). Here’s a simplified version of my model:
@Model
public final class ConnectorModel {
    public var connectorType: String
    ...
    func doSomethingDifferentForEveryConnectorType() {
       ...
    }
}
I’d like to implement doSomethingDifferentForEveryConnectorType in a way that allows the behavior to vary depending on connectorType, and I want to follow best practices for scalability and maintainability. I’ve come up with three potential solutions, each with pros and cons, and I’d love to hear your thoughts on which one makes the most sense or if there’s a better approach:
**Option 1: Use switch Statements
**
func doSomethingDifferentForEveryConnectorType() {  
    switch connectorType {  
    case "HTTP":  
        // HTTP-specific logic  
    case "WebSocket":  
        // WebSocket-specific logic  
    default:  
        // Fallback logic  
    }  
}
Pros: Simple to implement and keeps the SwiftData model observable by SwiftUI without any additional wrapping.
Cons: If more behaviors or methods are added, the code could become messy and harder to maintain.
**Option 2: Use a Wrapper with Inheritance around swiftdata model
**
@Observable  
class ParentConnector {  
    var connectorModel: ConnectorModel  
    init(connectorModel: ConnectorModel) {  
        self.connectorModel = connectorModel  
    }  
    func doSomethingDifferentForEveryConnectorType() {  
        fatalError("Not implemented")  
    }  
}  
@Observable  
class HTTPConnector: ParentConnector {  
    override func doSomethingDifferentForEveryConnectorType() {  
        // HTTP-specific logic  
    }  
}  
Pros: Logic for each connector type is cleanly organized in subclasses, making it easy to extend and maintain.
Cons: Requires introducing additional observable classes, which could add unnecessary complexity.
**Option 3: Use a @Transient class that customizes behavior
**
protocol ConnectorProtocol {  
    func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel)  
}  
class HTTPConnectorImplementation: ConnectorProtocol {  
    func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel) {  
        // HTTP-specific logic  
    }  
}  
Then add this to the model:
@Model  
public final class ConnectorModel {  
    public var connectorType: String  
    @Transient  
    public var connectorImplementation: ConnectorProtocol?  
    // Or alternatively from swiftui I could call myModel.connectorImplementation.doSomethingDifferentForEveryConnectorType() to avoid this wrapper
    func doSomethingDifferentForEveryConnectorType() {  
        connectorImplementation?.doSomethingDifferentForEveryConnectorType(connectorModel: self)  
    }  
}  
Pros: Decouples model logic from connector-specific behavior. Avoids creating additional observable classes and allows for easy extension.
Cons: Requires explicitly passing the model to the protocol implementation, and setup for determining the correct implementation needs to be handled elsewhere.
My Questions
Which approach aligns best with SwiftData and SwiftUI best practices, especially for scalable and maintainable apps?
Are there better alternatives that I haven’t considered?
If Option 3 (protocol with dependency injection) is preferred, what’s the best way to a)manage the transient property  2) set the correct implementation and 3) pass reference to swiftdata model?
Thanks in advance for your advice!
                    
                  
                
                    
                      I created 2 different schemas, and made a small change to one of them. I added a property to the model called "version". To see if the migration went through, I setup the migration plan to set version to "1.1.0" in willMigrate. In the didMigrate, I looped through the new version of Tags to check if version was set, and if not, set it. I did this incase the willMigrate didn't do what it was supposed to. The app built and ran successfully, but version was not set in the Tag I created in the app.
Here's the migration:
enum MigrationPlanV2: SchemaMigrationPlan {
    static var schemas: [any VersionedSchema.Type] {
        [DataSchemaV1.self, DataSchemaV2.self]
    }
    
    static let stage1 = MigrationStage.custom(
        fromVersion: DataSchemaV1.self,
        toVersion: DataSchemaV2.self,
        willMigrate: { context in
            let oldTags = try? context.fetch(FetchDescriptor<DataSchemaV1.Tag>())
            
            for old in oldTags ?? [] {
                let new = Tag(name: old.name, version: "Version 1.1.0")
                context.delete(old)
                context.insert(new)
            }
            
            try? context.save()
        },
        didMigrate: { context in
            let newTags = try? context.fetch(FetchDescriptor<DataSchemaV2.Tag>())
            for tag in newTags ?? []{
                if tag.version == nil {
                    tag.version = "1.1.0"
                }
            }
        
        }
    )
    
    static var stages: [MigrationStage] {
        [stage1]
    }
    
}
Here's the model container:
var sharedModelContainer: ModelContainer = {
        let schema = Schema(versionedSchema: DataSchemaV2.self)
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
        do {
            return try ModelContainer(
                for: schema,
                migrationPlan: MigrationPlanV2.self,
                configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()
I ran a similar test prior to this, and got the same result. It's like the code in my willMigrate isn't running. I also had print statements in there that I never saw printed to the console. I tried to check the CloudKit console for any information, but I'm having issues with that as well (separate post).
Anyways, how can I confirm that my migration was successful here?
                    
                  
                
                    
                      Are there any differences (either performance or memory considerations) between removing an array of model objects directly using .removeAll() vs using modelContext? Or, are they identical?
Attached below is an example to better illustrate the question (i.e., First Way vs Second Way)
// Model Definition
@Model
class GroupOfPeople {
   let groupName: String
   
   @Relationship(deleteRule: .cascade, inverse: \Person.group)
   var people: [Person] = []
   
   init() { ... }
}
@Model
class Person {
   let name: String
   var group: GroupOfPeople?
   
   init() { ... }
}
// First way
struct DemoView: View {
@Query private groups: [GroupOfPeople]
   var body: some View {
      List(groups) { group in
         DetailView(group: group)
      }
   }
}
struct DetailView: View {
   let group: GroupOfPeople
   var body: some View {
      Button("Delete All Participants") {
         group.people.removeAll()
      }
   }
// Second way
struct DemoView: View {
@Query private groups: [GroupOfPeople]
   var body: some View {
      List(groups) { group in
         DetailView(group: group)
      }
   }
}
struct DetailView: View {
   @Environment(\.modelContext) private var context
   let group: GroupOfPeople
   var body: some View {
      Button("Delete All Participants") {
         context.delete(model: Person.self, where: #Predicate { $0.group.name == group.name })
      } // assuming group names are unique. more of making a point using modelContext instead
   }