Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SharedState with UserDefaults(suiteName:) not working properly #3100

Closed
3 tasks done
rcasula opened this issue May 20, 2024 · 3 comments
Closed
3 tasks done

SharedState with UserDefaults(suiteName:) not working properly #3100

rcasula opened this issue May 20, 2024 · 3 comments

Comments

@rcasula
Copy link

rcasula commented May 20, 2024

Description

I'm trying to migrate an existing app to use the new SharedState functionality. My app uses an app group shared UserDefaults.

When I set the defaultAppStorage dependency to be $0.defaultAppStorage = UserDefaults(suiteName: ".."), I get some unexpected behaviour.
Seems like if I use even @Shared or @SharedReader in pushed views in a NavigationStack, doesn't update properly.

This is the structure that I have:
Home with a TabBar and 3 tabs. Each tab has a button to present a Settings screen with a sheet modal.
The Settings screen has a NavigationStack and pushes a new view ("ThirdView). The root SettingsView and the ThirdView contains a Picker that changes the default tab that has to be selected upon opening the app.

Using the UserDefaults(suiteName: "..") this happens:
If I change the value in the root SettingsView everything works as expected. But if I do it in the ThirdView, the value is not even updated if I go back to the previous screen (which is the root SettingsView).

Using the UserDefaults.standard, everything works as expected.

This is an example project that showcases this weird behaviour: https://github.com/rcasula/TCASharedStateShowcase

Seems that trying a similar example with @AppStorage works.

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Steps to reproduce

  1. Open the sample project https://github.com/rcasula/TCASharedStateShowcase
  2. Change the defaultAppStorage dependency to either .standard or the UserDefaults(suiteName: "..")
  3. Try updating the settings
  4. Observe the differences

The Composable Architecture version information

1.10.4

Destination operating system

iOS 17

Xcode version information

15.3

Swift Compiler version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0
@rcasula rcasula added the bug Something isn't working due to a bug in the library. label May 20, 2024
@OguzYuuksel
Copy link

OguzYuuksel commented May 20, 2024

There is little bit of work to complete / verify in the Appstore Connect to be able to use App groups. Did you complete that?
Do you try it with an erased simulator? So you don't have any previous cache.

@rcasula
Copy link
Author

rcasula commented May 21, 2024

There is little bit of work to complete / verify in the Appstore Connect to be able to use App groups. Did you complete that? Do you try it with an erased simulator? So you don't have any previous cache.

What kind of work are you referring to? Usually Xcode is taking care of updating the provisioning profile correctly, when you add the capability.
Using @AppStorage directly in a vanilla SwiftUI project (see the example repo that I shared) works even with the AppGroup configured.

@stephencelis
Copy link
Member

@rcasula The third view is being instantiated like so:

NavigationLink("Third view") {
  ThirdView(store: .init(initialState: .init()) { Third() })
}

This store is completely independent of the root store and doesn't share its dependencies unless you explicitly pass it along.

If ThirdView took a store that was scoped from the parent it should work just fine.

Alternately, if you require spinning up a new store you need to use withDependencies: again. Observation across both stores requires the same user defaults object, though, since it is done via KVO. I think that UserDefaults.init(suiteName:) will create a new object each time, so you would want to create a static that preserves the object for the lifetime of the app:

extension UserDefaults {
  static let mySuite = UserDefaults(
    suiteName: "group.dev.casula.TCA.SharedStateShowcase"
  )!
}

// ...

let store = Store(initialState: .init()) {
  Home()
} withDependencies: {
  $0.defaultAppStorage = .mySuite
}

// ...

ThirdView(store: .init(initialState: .init()) {
  Third()
} withDependencies: {
  $0.defaultAppStorage = . mySuite
}

Because this is not a bug and just how TCA and user defaults work, I'm going to convert to a discussion.

@stephencelis stephencelis removed the bug Something isn't working due to a bug in the library. label May 21, 2024
@pointfreeco pointfreeco locked and limited conversation to collaborators May 21, 2024
@stephencelis stephencelis converted this issue into discussion #3105 May 21, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants