You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.
As local state updates are synchronous, an interaction call inside View_A.update(oldModel:) can cause unordered nested updates and unexpected bugs 😱.
Let's say a generic state change has started an update cycle (0): state_0 and localState_0 are used to compute rootViewModel_0, and inherently viewModel_A_0 and viewModel_B_0
rootView.model = rootViewModel_0 and rootView.update() begins
view_A.model = viewModel_A_0
view_A.update() begins
During view_A.update, the increment interaction is called, causing a nested update cycle (1)
state_0 and localState_1 are used to compute rootViewModel_1
rootView.model = rootViewModel_1 and rootView.update() begins
view_A.model = viewModel_A_1 and viewA.update() is executed
view_B.model = viewModel_A_1 and viewB.update() is executed
`rootView.update() ends
Update cycle 1 ends, update cycle 0 continues
viewA.update() is resumed (**)
viewA.update() ends
view_B.model = viewModel_B_0 and viewB.update() is executed (*)
`rootView.update() is resumed (***)
`rootView.update() ends
Update cycle 0 ends
Problems
At the end:
View_B is one view model behind (*)
If we use a copy of the view model inside view_A.update() (e.g. we use guard let model = self.model), a part of the old model can be applied on top of the latest model. (**)
The same considerations of 2 apply to RootView (***)
While debugging, this behaviour is counter-intuitive in respect to the normal update cycle
Usually view hierarchies are more complex
There could be more levels of nested updates
Finding and fixing these kinds of bugs can be just difficult and really time consuming 🤕
Possible Solutions
I see two way to address this issue:
consider changing the local state during a model update an anti-pattern or a programming error and perform an assertion.
Is this kind of setup ever useful (maybe to interact with some UI related framework with observers/callbacks/delegates) or it is just the consequence of a bad design?
enqueue incoming LocalState to avoid nested update cycle
I'm not keen on a particular solution, both seems easy to implement.
The issue is about
LocalState
updates performed inside aModellableView
'supdate()
method.Example
This is an example Tempura UI
View_A
andView_B
inherently depends onLocalState
.View_A
has an interaction that updates theLocalState
As local state updates are synchronous, an interaction call inside
View_A.update(oldModel:)
can cause unordered nested updates and unexpected bugs 😱.Let's say a generic state change has started an update cycle (0):
state_0
andlocalState_0
are used to computerootViewModel_0
, and inherentlyviewModel_A_0
andviewModel_B_0
rootView.model = rootViewModel_0
androotView.update()
beginsview_A.model = viewModel_A_0
view_A.update()
beginsview_A.update
, theincrement
interaction is called, causing a nested update cycle (1)state_0
andlocalState_1
are used to computerootViewModel_1
rootView.model = rootViewModel_1
androotView.update()
beginsview_A.model = viewModel_A_1
andviewA.update()
is executedview_B.model = viewModel_A_1
andviewB.update()
is executedviewA.update()
is resumed (**)viewA.update()
endsview_B.model = viewModel_B_0
andviewB.update()
is executed (*)Problems
At the end:
view_A.update()
(e.g. we useguard let model = self.model
), a part of the old model can be applied on top of the latest model. (**)RootView
(***)Finding and fixing these kinds of bugs can be just difficult and really time consuming 🤕
Possible Solutions
I see two way to address this issue:
I'm not keen on a particular solution, both seems easy to implement.
┆Issue is synchronized with this Asana task by Unito
The text was updated successfully, but these errors were encountered: