Hi,
I’m looking for clarification on what concurrency and consistency guarantees Apple provides when multiple targets (main app + Widget extensions) access shared storage.
Specifically: 1. UserDefaults (App Group / suiteName:) • If multiple processes (app + multiple widget instances) read and write the same shared UserDefaults, what guarantees are provided? • Is access serialized internally to prevent corruption? • Are read–modify–write operations safe across processes, or can lost updates occur? 2. Core Data (shared SQLite store in App Group container) • Is it officially supported for multiple processes to open and write to the same Core Data SQLite store? • Are there recommended configurations (e.g. WAL mode) for safe multi-process access? • Is Apple’s recommendation to have a single writer process? 3. FileManager (shared container files) • If two processes write to the same file in an App Group container, what guarantees are provided by the system? • Is atomic replaceItemAt the recommended pattern for safe cross-process updates?
Additionally: • Do multiple widget instances count as separate processes with respect to these guarantees? • Is there official guidance on best practices for shared persistence between app and widget extensions?
I want to ensure I’m following the correct architecture and not relying on undefined behavior.
Thanks.
Your questions are quite hard to read. See Quinn’s Top Ten DevForums Tips for advice on how to improve this going forward.
Also, you asked questions about four very different technologies: User defaults, Core Data, the file system, and widgets. I have a good handle on the first and the third. I can offer some general advice about the second but, if you want more then you should start a follow-up thread in App & System Services > iCloud & Data with the Core Data tag. Similarly for the fourth, but with the App & System Services > Widgets & Live Activities subtopic.
With that out of the way, let’s look at your questions.
User defaults has a last-write-wins synchronisation policy, with the caveat that the definition of “last” is last change to hit the daemon that manages this stuff. The answers to your question fall out of that policy:
If multiple processes (app + multiple widget instances) read and write the same shared UserDefaults, what guarantees are provided?
That one of them will win.
Is access serialized internally to prevent corruption?
Yes, on a default-by-default basis. That is, a given user default is guaranteed to end up with one of the values you wrote to it.
Are read–modify–write operations safe across processes … ?
No. User defaults offers neither a locking mechanism nor a transaction mechanism, so there’s nothing to protect read-modify-write operations from being interspersed.
On the Core Data front you wrote:
Is it officially supported for multiple processes to open and write to the same Core Data SQLite store?
Yes. This has been a long-standing pattern in Core Data.
Your other questions are about best practices and I’m not the right person to answer those.
On the file system front:
If two processes write to the same file in an App Group container, what guarantees are provided by the system?
That very much depends on how they do the writing.
Is atomic replaceItemAt the recommended pattern for safe cross-process updates?
It is a reasonable pattern. However, there are many others.
Notably, many of our low-level types, like Data and String, have a write method that accepts an .atomic flag (for example, this), and these might be easier to use.
There are also more advanced techniques: lock files, file locking, journalling, and so on.
Which is the best option very much depends on your specific requirements.
Do multiple widget instances count as separate processes with respect to these guarantees?
AFAIK this isn’t documented anywhere, which makes it an implementation detail, and thus I’d recommend that you err on the side of caution.
Is there official guidance on best practices for shared persistence between app and widget extensions?
I’m not the right person to answer this.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"