Closed bcapps closed 1 month ago
Hi @bcapps, thanks for raising this. This is kind of a known issue at the moment but we're not sure the right way to proceed given the underlying behavior of user defaults. We've chosen the firehose subscription to Notification Center route so that keys like "compound.key"
still work, but it has the trade-off you mention.
I'd be curious if you've explored the behavior of @AppStorage
in SwiftUI. It seems to support "compound.key"
key names, so I'm wondering if it also has problems with extensions or if it somehow works around the issue. Can you look into the behavior of @AppStorage
in extensions and report back?
Now one thing we could explore is a "hybrid" solution of sorts, where if the key contains a period we do a firehose subscription, and otherwise we do a direct KVO subscription. This is of course a tricky line to walk, though, where the format of the key leads to a completely different code path, and so we're not sure it's advisable, and we'd need to be careful to document the difference. Ideally user defaults would provide a better universal solution here, but we're not aware of it.
One option you have would be to copy and paste the source of AppStorageKey
into your project, give it a new name, and swap out the firehose notification for KVO. It should compile in full isolation.
For now I'm going to convert this to a discussion since it is the current expected behavior, but we are open to better solutions here if anyone has ideas.
Description
Recently, we were attempting to use
@Shared(.appStorage(key))
with several TCA reducer properties in a widget extension, having already used it successfully in the parent app. We updateddependencies.defaultAppStorage
to our own UserDefaults with the correct suite in both the main app and extension, and while this allowed the correct value to be read into each property in the widget initially, the extension never receives updates when the main app writes to the defaults.While tracing down this issue, we found that it was due to the implementation of
AppStorageKey
: it's usingUserDefaults.didChangeNotification
to observe changes and update the value, but this notification is documented to not work across processes. Therefore, the values in the extension never update as expected.The documentation points to KVO as the solution for observing changes even across processes, but it has the very annoying issue that keys with periods won't work due to key paths using periods differently. I tried a solution of this nature and failed on the included test with a key containing periods. So I'm not sure what the correct answer is here, but I think it is somewhat expected that
@Shared(.appStorage(key))
properties in an extension with a shared app group would update so I'm filing this issue.Checklist
main
branch of this package.Expected behavior
@Shared(.appStorage(key))
properties on TCA reducers used in extensions stay in sync with the main app values whendefaultAppStorage
usesUserDefaults(withSuite:)
Actual behavior
@Shared(.appStorage(key))
properties on TCA reducers used in extensions are correct initially, and then are out of sync with the main app values whendefaultAppStorage
usesUserDefaults(withSuite:)
Reproducing project
No response
The Composable Architecture version information
main
Destination operating system
iOS 18
Xcode version information
Xcode 16
Swift Compiler version information