5

The documentation for App Extension under "Sharing Data with Your Containing App" uses NSUserDefaults to do so, and write a bit further that

"to avoid data corruption, you must synchronize data accesses. Use Core Data, SQLite, or >Posix locks to help coordinate data access in a shared container."

But when I look documentation for NSUserDefaults says

"The NSUserDefaults class is thread-safe."

So do I need to use some kind of lock when using NSUserDefaults between my extension and container app or not?

user2962499
  • 486
  • 6
  • 10

3 Answers3

6

Thread safety refers to the ability to change in-memory data structures from one thread in a way that doesn't damage the ability of other threads to also view or change those structures. When you use NSUserDefaults to share data between an app extension and its containing app, you're not sharing in-memory data between multiple threads, you're sharing on-disk data between multiple processes, so discussions of thread safety do not apply.

The documentation for NSUserDefaults synchronize doesn't say for sure, but one can almost certainly assume that it uses an atomic file write — that is, there's no danger of one process reading a file that's been partially written by another process. If you're concerned about race conditions or other timing issues between when your app writes defaults and your extension reads them (or vice versa), just be sure to synchronize immediately after important writes and immediately before important reads.

The comment about data corruption applies to plain file read/write operations — naively reading or writing a file in two processes can result in data corruption, because one process might read a partially written file or partially overwrite file contents. If you're doing your own file I/O directly, you need some sort of coordination mechanism (like NSFileCoordinator, but beware that only works correctly between iOS apps/extensions in iOS 8.2 and newer). Or you can use higher level utilities that do their own coordination, like CFPreferences/NSUserDefaults, SQLite, Core Data, or Posix file locks.

TLDR: Yes, you can safely use NSUserDefaults to share between an extension and its containing app. Just follow the recommendations in Apple's app extensions guide.

rickster
  • 124,678
  • 26
  • 272
  • 326
1

The documentation isn't overly clear, as it uses the NSUserDefaults as the main example of one way to share data but also covers other options without much of a pause. You should be safe enough to use NSUserDefaults without attempting to get a lock first, I've been building a Today extension using it and I've had no issues with data corruption. I am calling synchronize after each write though, just to ensure the data is immediately stored.

Nicholas Smith
  • 11,642
  • 6
  • 37
  • 55
0

I am not sure if it is thread safe across extensions because of the following quote from docs:

When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes.

In other words, it seems to indicate that it's thread-safe within your process, but NOT across processes (ex. extensions).

It could be that calling synchronize fixes this, but docs say:

this method is unnecessary and shouldn't be used

kgaidis
  • 14,259
  • 4
  • 79
  • 93