-
-
Notifications
You must be signed in to change notification settings - Fork 17
Description
Checklist
- This is not a bug caused by platform.
- Reviewed the README and documentation.
- Checked existing issues & PRs to ensure not duplicated.
What happened?
(I apologize if this is not a bug, I wasn't sure which category of issue to file this under.)
(I have been using Atoms for a few weeks, with zero issues. I've been able to get almost everything working except this one last thing. I got a stuck on it a week ago, left it and moved on, but now I've come back to it and after a day of trying to get it working, I'm stumped.)
Context:
- I have an AccountStore, (most of which was copied from the Apple Passkey Sample Code) that is working correctly (when I use it as an EnvironmentObject. Here is part of it, shortened for brevity:
public final class AccountStore: NSObject, ObservableObject, ASAuthorizationControllerDelegate {
@Published public private(set) var currentUser: User? = .default
@MainActor
public func signIn(username: String) async throws {
// ...
}
@MainActor
public func signOut() {
// ...
}
// ...
}- Since I've managed to move the rest of my data model over to Atoms, the only thing left is Auth & fetching the User (Player). Here are the Atoms I created in order to try to do this:
struct AccountStoreAtom: ObservableObjectAtom, Hashable {
func object(context: Context) -> AccountStore {
AccountStore()
}
}
struct FetchPlayerAtom: ThrowingTaskAtom, Hashable {
func defaultValue(context: Context) -> Player? {
return nil
}
func value(context: Context) async throws -> Player {
print("FetchPlayerAtom().value")
return try await BackendAPI.fetchPlayer()
}
}
struct PlayerAtom: ValueAtom, Hashable {
func value(context: Context) -> Player? {
let accountStore = context.watch(AccountStoreAtom())
print("PlayerAtom().value", accountStore.currentUser as Any)
if case let .authenticated(username) = accountStore.currentUser {
print("PlayerAtom().value.authenticated()", username)
let fetchPlayerPhase = context.watch(FetchPlayerAtom().phase)
if case let .success(player) = fetchPlayerPhase {
print("PlayerAtom().value.success()", player)
return player
}
}
return nil
}
}
struct GameScreenAtom: ValueAtom, Hashable {
func value(context: Context) -> GameScreen {
let player = context.watch(PlayerAtom())
print("GameScreenAtom().value", player as Any)
if player == nil {
return .mainMenu
}
if player!.isPlaying {
return .homeBase
}
return .setupNew
}
}Expected Behavior
After logging in, the AccountStore publishes to currentUser, setting it to authenticated.
I expect that:
- The PlayerAtom(), which is watching AccountStoreAtom(), would notice that currentUser was updated. (Not happening)
- Then it would watch the FetchPlayerAtom(), and return the Player after it's fetched.
- Finally, the GameScreenAtom(), which is watching the PlayerAtom(), would notice that a Player now exists, and would set the gameScreen accordingly.
Reproduction Steps
I don't have a great way to help you reproduce this yet, I'm hoping that you can spot if I'm doing anything incorrectly in my code. If not, then I'll try to put together a reproducible example.
I'm attaching a Screen Recording of this. If you watch it, please play attention to the orange 🏗 Debug Values at the top of the screen. You will note that when the EnvObject.currentScreen updates (which is computed in the same way, from the AccountStore), the Atom.GameScreen does not.
Swift Version
5
Library Version
0.2.0
Platform
iOS