huh, working on my swift code a bit, trying to get...
# decompose
a
huh, working on my swift code a bit, trying to get some navigation going, but the UI isn't reacting to the router state updating.
Copy code
@ObservedObject
    private var routerState: ObservableValue<ChildStack<AnyObject, ProjectRootDestination<AnyObject>>>
Copy code
private val stack = componentContext.childStack(
		source = navigation,
		initialConfiguration = Config.HomeConfig(projectDef),
		key = "ProjectRootRouter",
		childFactory = ::createChild
	)

	val state: Value<ChildStack<Config, ProjectRoot.Destination<*>>>
		get() = stack

	fun showNotes() {
		navigation.bringToFront(Config.NotesConfig(projectDef = projectDef))
	}
I'm thinking it's because calling
navigation.bringToFront
isn't actually reassigning the variable maybe?
a
Which variable? You can check the root component in samples.
a
ya I was looking at counter example, but looking at the root one now, that seems much closer to what im doing here
I even was just printing out which child was active in a textview, and it prints the initial one, but it never changes as I trigger navigations
hhmmm the main difference is that I'm using a StackView maybe
a
Yeah, please try without StackView
a
even still, stackview aside, that text view isn't even updating
i just changed it to use that computed field:
Copy code
let curDest = destinationTitle(dest: activeDestination)
            Text(curDest)
but no dice
a
What if you remove
Text("project root")
?
Also you can try adding logs everywhere, and see where it stops propagating
a
im still working on this, logging on ios from kotlin wasnt working for me at first but i got that solved.
i've got it logged down to where i make the navigate call, and thats all working
a
Does Value emits the updated state on the Swift side?
a
i dont think so, but i still need to verify that
havent had a lot of time the last few days so havent been able to check much
a
It would be useful if you could check that. Also worth checking any errors in Xcode logs.
a
this should capture any update on the swift side I think:
Copy code
init(component: ProjectRoot, closeProject: @escaping () -> Void) {
        self.component = component
        self.routerState = ObservableValue(component.routerState)
        
        component.routerState.subscribe { stack in
            NSLog("swift router state update")
        }
    }
as long as thats not wrong in some way, then the update is never getting back to the swift side of things
I see the initial state update in that subscribe, but nothing after
a
Is the back reproducible on github?
a
ya, this branch is where the ios work is: https://github.com/Wavesonics/hammer-editor/tree/bbooth-dev
im guessing there is no good way to debug into kotlin code from an ios build?
wonder if its a threading issue or something...
a
I remember there was KMP plugin for IDEA, but I never used it.
Let me check the project
a
ProjectRootUi.swift
is the main swift file here
ProjectRootComponent.kt
is where the router lives
maybe I'm not initializing something, like the lifecycle stuff
huh i think it might be lifecycle related, im getting onDestroy called right after init
a
Yep, when the parent is destroyed, all routers unsubscribe from navigation sources (e.g.
StackNavigation
)
a
ah and that makes sense
a
You can add
lifecycle.doOnDestroy { Exception().printStackTrace() }
to identify the cause.
Let me know if you still need any help.
a
awesome, thanks for pointing me in the right direction!
so I think the issue is that I was creating the component holder in the UI body function, so when it updates, it creates a new component, thus destroying the old one
my use case here is a bit strange, I have two top level Components. on Desktop there are two separate windows, on android two separate Activities. on iOS they are currently just switched between based on state in the SwiftUi code it's self. So I need to find a way to create or destroy these components based on the state updates. Pretty new to both swift and swift UI, so probably just writing some hilarious naive code here
ya moved the component creation out, looks like its working now
a
Makes sense! You can try wrapping both roots into a separate struct that extends ObservableObject. Then put that wrapper into a separate View with StateObject annotated property. You can also expose component states from wrappers using State property.
a
ya that sounds like pretty much what i did, they just live in this state obj now: https://github.com/Wavesonics/hammer-editor/blob/bbooth-dev/ios/ios/Root.swift#L12
a
It looks like you can avoid MutableValue in your RootHolder. You can have @Published property.
a
oh ya good call
i have no idea what im doing in swift 😂