

And it is a pretty big violation of the dependency inversion principle. If we were to use delegation for this issue, the solution is conceptually trivial but adds a lot of code in files that shouldn’t care about onboarding. Implementing this behavior with delegation However, both of these approaches have some pretty glaring weaknesses in their respective architectures. Then we would also subscribe to those relays from onboarding. Or, we could utilize a framework like RxSwift to create relays to pass down to the relevant components and publish from there. As a naive solution, we could delegate up to the common ancestor of the onboarding branch of the tree, and a given UI component would then call down to onboarding. When we first encountered this problem, we saw two potential implementations. Don’t worry too much about the components in the middle-they’re just there to convey that there are many layers to the component tree.Īs you can see, for our onboarding UI to monitor the assistant overlay, we need to pass information between distant cousins on opposite ends of the component tree.


Our OnboardingController handles the onboarding logic, and the AssistantViewController is the assistant overlay. When we’re in a state like this, our application’s component tree will look something like the following: Our onboarding UI needs to get information about the overlay so that it can draw the arrow correctly and hide the arrow when the overlay disappears. The overlay can appear and disappear as the user switches windows. In the example above, the card overlay is a completely separate window on top of the onboarding UI. Because of this, in our Grammarly for Mac app we have many states where two windows will conditionally rely on each other only if they are instantiated.ĭuring onboarding, green arrows on screen point to different UI elements. Windows may also appear and disappear regularly. On desktop, as opposed to mobile, it’s common to have states where multiple windows are on screen at once.
