Hello,
I am encountering an issue with user-generated files stored in the Documents directory on an iPhone 11 running iOS 18.2.
The problem occurs as follows:
1.The app generates and saves files in the Documents directory using FileManager.
2.These files are successfully saved and remain accessible while the app is running.
3.After restarting the app, the files appear to have been deleted from the Documents directory.
I have confirmed that:
1.The files are being saved to the correct location (Documents directory) and can be accessed during the current app session.
2.The app is not explicitly deleting these files during shutdown or restart.
3.This behavior is consistent across multiple app restarts.
Cloud and Local Storage
RSS for tagStore data locally or in the cloud.
Posts under Cloud and Local Storage tag
49 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi,
I'm building a habit tracking app for iOS and macOS. I want to use up to date technologies, so I'm using SwiftUI and SwiftData.
I want to store user data locally on device and also sync data between device and iCloud server so that the user could use the app conveniently on multiple devices (iPhone, iPad, Mac).
I already tried SwiftData + NSPersistentCloudKitContainer, but I need to control when to sync data, which I can't control with NSPersistentCloudKitContainer. For example, I want to upload data to server right after data is saved locally and download data from server on every app open, on pull-to-refresh etc. I also need to monitor sync progress, so I can update the UI and run code based on the progress. For example, when downloading data from server to device is in progress, show "Loading..." UI, and when downloading finishes, I want to run some app business logic code and update UI.
So I'm considering switching from NSPersistentCloudKitContainer to CKSyncEngine, because it seems that with CKSyncEngine I can control when to upload and download data and also monitor the progress.
My database schema (image below) has relationships - "1 to many" and "many to many" - so it's convenient to use SwiftData (and underlying CoreData).
Development environment: Xcode 16.1, macOS 15.1.1
Run-time configuration: iOS 18.1.1, macOS 15.1.1
My questions:
1-Is it possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud?
2-If yes, is there any example code to implement this?
I've been studying the "CloudKit Samples: CKSyncEngine" demo app (https://github.com/apple/sample-cloudkit-sync-engine), but it uses a very primitive approach to local data storage by saving data to a JSON file on disk.
It would be very helpful to have the same demo app with SwiftData implementation!
3-Also, to make sure I don't run into problems later - is it okay to fire data upload (sendChanges) and download (fetchChanges) manually with CKSyncEngine and do it often? Are there any limits how often these functions can be called to not get "blocked" by the server?
4-If it's not possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud, then what to use for local storage instead of SwiftData to sync it with iCloud using CKSyncEngine? Maybe use SwiftData with the new DataStore protocol instead of the underlying CoreData?
All information highly appreciated!
Thanks,
Martin
I have already built an app using SwiftData and now I want to introduce CloudKit features in it, what should I do? I'm totally new to this part. Thank you!
My MacBook Pro M2 is fast running out of space. The system data is currently 260 Gb. I'm using macOS Sequoia Beta 15.2. All my other data files are in total about 100Gb. I have already deleted cache files. I have also reinstalled the OS software. What else can I do to get my storage space back
I'm using SwiftData, and I'm using iCloud's CloudKit feature to back up my data.
The problem here is that once you start backing up your data, you can't erase it completely.
Even if the user adds 4 data and erases 4 again, I'm using about 2.5kb.
I don't know how the user using the app will accept this.
I'm trying to provide the user with the ability to erase data at once, what should I do??
iPhone 15pro iOS 18.2
Downloaded files cannot be located anywhere in Files, only by accessing Downloads in Safari. I have tried setting download folder to various locations, iCloud, Phone, Google Disk, but nothing is stored.
Has an invisible cache or temp folder been introduced? If so, it is a total fail:
When press-holding any file in Safari download, the normal file action options (Quick Look, share, store to Files, etc) are not available.
When clicking any file it opens any of several apps that has this file type associated with it, and there is no way to change the default app or disable the forced opening of an app.
I tried deleting the app opening .csv (in this case OneDrive), and another irrelevant app opened. There seems to be a hierarchy of apps-file types, and it has no logic to it.
in Chrome behaviour is as expected.
Chrome vs. Safari screen recordings: https://shorturl.at/my3Oy
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?
Hey,
I am fairly new to working with AVFoundation etc. As far as I could research on my own, if I want to get metadata from let's say a .m4a audio file, I have to get the data and then create an AVAsset. My files are all on local servers and therefore I would not be able to just pass in the URL.
The extraction of the metadata works fine - however those AVAssets create a huge overhead in storage consumption. To my knowledge the data instances of each audio file and AVAsset should only live inside the function I call to extract the metadata, however those data/AVAsset instances still live on on storage as I can clearly see that the app's file size increases by multiple Gigabytes (equal to the library size I test with). However, the only data that I purposefully save with SwiftData is the album artwork.
Is this normal behavior for AVAssets or am I missing some detail?
PS. If I forgot to mention something important, please ask. This is my first ever post, so I'm not too sure what is worth mentioning.
Thank you in advance!
Denis
I have a homepage with an iframe containing my app LocalStorage,
but when opening my app page the LocalStorage is lost.
structuration of the page:
homepage : domain.com
iframe and app : app.domain.com
the localstorage is set up directly within the iframe and postmessage between iframe and parent works.
We see in the parent page that the LocalStorage for the sub-domain is set but opening the sub-domain on a new window it disappears :
The problem is detected On Safari 18 only.
Hi Team,
I am trying to explore ESF events specifically generated by cloudsync extensions built on File Provider framework.
Brief:
I have high-level understanding of how various cloud vendors have provided their extensions to sync data from cloud/remote storage to local filesystem (and vice-versa). e.g.iCloudDriveFileProvider (icloud), DFSFileProviderExtension (google drive).
There are 2 ESF AUTH events for file provider I can see namely: ES_EVENT_TYPE_AUTH_FILE_PROVIDER_MATERIALIZE ,
ES_EVENT_TYPE_AUTH_FILE_PROVIDER_UPDATE.
and respectively their NOTIFY events.
Observation:
Observed that these events are generally triggered by fileproviderd process during download scenario i.e. syncing files from cloud/remote storage to local file system. i.e. 'materialize' for new file creation and 'update' for updating existing file.
Question/Problem:
Is there a correct way to find which cloud provider has triggered this download event? i.e. weather it is iCloudDriveFileProvider or DFSFileProviderExtension (there is this instigator field in Materialize event struct, but could not find similar for Update event.
Are there similar ESF events for upload scenario? (I have fair understanding of how file-to-upload is copied to temp location and then uploaded by respective extensions to remote storage, but then they work with original files clone created in their temp location, so the AUTH events generated by this extension will wont reveal the original file name even if I am able to get the Fileprovider name)
To Summarize: Basically I am looking for ESF event that will be triggered during upload scenario that can also let me know original file name as well the cloudprovider extension process name. As of now 'fileproviderd' process name is obtained from filesystem ESF events like AUTH_OPEN etc.
My app saves its document files by default into ~/Documents. It does some important domain-specific stuff when a document is deleted. I monitor for deletion using https://github.com/eonist/FileWatcher
Unfortunately several users have noticed my app doing this cleanup work even when they have not deleted the corresponding document. We've traced it through and realised it's the iCloud "Optimise Mac Storage" feature, or "Store in iCloud > Desktop and Documents". I'm not sure which because I don't use these features of macOS at all, and also they seem to have been renamed or changed in Sonoma.
Either way, I'm wondering:
a) how I can tell in Swift whether a file has actually been deleted, or whether it's been "offloaded" to iCloud by macOS.
b) how can I test this?
My research is pointing at urlubiquitousitemdownloadingstatus but it's hard to play with it without knowing how to test it.
I create a CKShare and then I set the title:
share[CKShare.SystemFieldKey.title] = title
I even call:
if let cloudStore = coreDatabase.cloudStore {
try await persistentContainer.persistUpdatedShare(share, in: cloudStore)
}
but when I retrieve this share again using
persistentContainer.fetchShares(matching: [id])
the title is not set. I even checked CloudKit console and I can't see there title either...
How can I retrieve the previously set title for a share?
It is possible to append a record to a CKShare using
NSPersistentCloudKitContainer.share(objects, to: share)
but how can I reverse this operation and remove the object from share?
The workaround would be to delete and recreate the object, but is there any SDK function to do it right? The more I work with CoreData+CloudKit the more it seems like everything there is a workaround or hack or bug... This SDK is still in Alpha at best.
I need to know which records belong to a specific CKShare. I can retrieve a share for a single record, but then having the CKShare I can't check what other records belong to it.
Is there any better way to do it without fetching shares for the whole database and grouping them?
MacBook Air black screen
On top of unstable CloudKit sync, we've got also extremely unstable sharing/collaboration functionality.
I mean, it's quite impressive how easy it is to enable sharing, but this feature should not be released at this point. It feels like using software in the alpha version.
Let's take NSPersistentCloudKitContainer.share(_:to:) (https://developer.apple.com/documentation/coredata/nspersistentcloudkitcontainer/3746834-share), the documentation says:
Sharing fails if any of the following conditions apply:
Any objects in managedObjects, or those the traversal finds, belong to > an existing share record.
However, it's wrong... if you pass any object from the existing share, it will return the same share... It never fails in this case.
Things are getting even weirder if you experiment a little bit with shares. So let's assume you share a couple of objects:
persistentContainer.share([A, B, C, D], to: nil)
Now you stop sharing those via UICloudSharingController and you want to share again but just C. So you call:
persistentContainer.share([C], to: nil)
and surprise, surprise, you get a new share URL, but you share all previously shared objects (A, B, C, D), not as you would have expected only C...
On top of that, you keep getting some weird errors like:
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](2190): <NSCloudKitMirroringDelegate: 0x3029b84b0> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringExportRequest: 0x30359f1b0>123123123123' due to error: <CKError 0x3018699b0: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = 12312312312312; container ID = "iCloud.some.id"; partial errors: {
com.apple.coredata.cloudkit.share.123123123123123:__defaultOwner__ = <CKError 0x30186a3d0: "Invalid Arguments" (12/2006); server message = "Only shared zones can be accessed in the shared DB"; op = 12312312312312; uuid = 123123123123>
}>
Even though the only thing I use is
persistentContainer.share
and
UICloudSharingController(share: share, container: cloudKitContainer)
And the cherry on the top, from time to time if you play a little with sharing multiple objects at once, it happens that it randomly wipes out some records from that share...
I don't even know where to start reporting issues and if its worth it, because every ticket will be dismissed anyway because "we need thousands of your logs, we require you to do all the job for us".
Is there any version of UICloudSharingController available on macOS or do we need to handle it manually?
How to manually configure a share and send an invitation from macOS?
What is the recommended way of intercepting and processing errors?
As far as I know, there are 4 main areas:
iCloud account status - this can be checked and intercepted via notifications
exceptions from fetch/execute/save - it can be a simple do..catch, but what exceptions can we expect here, what should be handled, and how?
there could be some asynchronous issues with synchronization. How should we intercept them and how should they be handled?
issues with iCloud storage - quota exceeded, etc. How to intercept & handle those?
I'm trying to achieve production-ready implementation, but there are many pitfalls and hidden issues that are not well documented. Could you provide some advice on how to handle properly all these situations?
Hello,
I'm using NSPersistentCloudKitContainer. If the user disables iCloud sync for my app in the system settings and opens the app, all records are immediately wiped out, even if there are unsynced changes (like records added offline).
Disabling iCloud sync doesn't even show any warning, so the user may lose all data (if it's not already synced to Cloud).
Is it possible to intercept that the store will be wiped out when the app is launching? I would copy all records to the local storage then to avoid losing data by the user.
CloudKit sync is very unstable. Sometimes it just stops syncing for no reason, other times it works almost instantly.
The core issue with synchronization is that CoreData relies mostly on two things:
silent push notifications, which are by design unreliable and can be throttled
user interactions, I noticed that the local database is updated most likely periodically and also based on some app events like entering the foreground.
Unfortunately, there is no SDK function that allows us to force sync with CloudKit, which basically prevents us from providing some features to recover if a user encounters problems.
After thousands of tests, I finally discovered what was wrong and how to make the synchronization stable. Basically, I noticed that at some point CoreData decides that it won't synchronize data unless you deactivate and activate the application, which is crazy. It's getting even worse if we talk about extensions like the keyboard extension on iOS. The same happens on all platforms.
Therefore, knowing that I implemented a trick that happened to work perfectly. The workaround requires to periodically sending an event pretending that the app is going foreground.
macOS:
var cancellable = Set<AnyCancellable>()
// ...
Timer.publish(every: 20.0, on: RunLoop.main, in: .common)
.autoconnect()
.sink { _ in
NotificationCenter.default.post(.init(name: NSApplication.willBecomeActiveNotification))
}
.store(in: &cancellable)
iOS:
var cancellable = Set<AnyCancellable>()
// ...
Timer.publish(every: 20.0, on: RunLoop.main, in: .common)
.autoconnect()
.sink { _ in
NotificationCenter.default.post(.init(name: UIApplication.didBecomeActiveNotification))
}
.store(in: &cancellable)
After that, everything works perfectly. Pitty that the solution mostly meant for enterprise is so unstable and there is not even a single SDK function to recover from that (force sync).
Any plans to fix CoreData+CloudKit? I also created a ticket: #FB14531806.