-
Notifications
You must be signed in to change notification settings - Fork 135
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
RUMM-2964 [SR] Make view-tree recording more customizable #1175
RUMM-2964 [SR] Make view-tree recording more customizable #1175
Conversation
7567895
to
17de653
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea, and testing is on point!
What I don't understand tho is how you will create the .replace
strategy when recording 🤔 The UIPickerViewRecorder
will need to depend on a UILabelRecorder
for creating the nodes?
Not directly, but yes. The In pseudocode, the root view (app window) could use: let appWindowSubtreeRecorder = ViewTreeRecorder(
nodeRecorders: [
UIViewRecorder(),
UILabelRecorder(),
UISwitchRecorder(),
UIToggleRecorder(),
UITabBarRecorder(),
UIImageViewRecorder(),
// ...
UIPickerViewRecorder()
]
) And any concrete recorder can specify its own list of expected nodes, e.g.: let pickerSubtreeRecorder = ViewTreeRecorder(
nodeRecorders: [
UIViewRecorder(),
UILabelRecorder(),
]
) This way, the The Main idea here is to achieve composable architecture, so compelx node recorders could reuse simple ones in their own subtrees. An alternative to this would be making each node recorder heavily parameterized, for example adding an option in Hope it makes it cleaner now @maxep - LTM! |
Yes, I see! Then I'm concerned about having 2 logics for recording, one 'kind' of recorder won't depend on other recorders and will just delegate the tree traversing to its caller, they will return the root node semantics only. The other kind will depend on its own set of recorders and will provide the root node semantics and its children nodes. If we generalise, we could say that a recorder is responsible for traversing the view tree, it could use all default recorders (equivalent to strategy internal protocol NodeRecorder {
/// - Returns: The full list of nodes representing the view and subviews.
func nodes(of view: UIView, with attributes: ViewAttributes, in context: ViewTreeRecordingContext) -> [Node]
} Recorders would use helper functions to traverse the subviews recursively, and they will decide what nodes to return, they will use the provided attributes and semantics they found. It's a bigger refactor I admit, so I left it as a suggestion but I believe it will scale better as we add more and more recorders. LMWYT! |
As we discussed on the meeting - it is an interesting proposal and a bit aligned with current design 👍. We may want to look into it later - for now we think it is best to cover more use cases with current architecture before considering a shift. We're still learning the complexity of views hierarchy and discovering more arch drivers. |
What and why?
📦 This PR adds more flexibility to the way SR traverses and records subtree hierarchies.
This change will allow each
NodeRecorder
(e.g.UIViewRecorder
orUILabelRecorder
) defining their own strategies and will be soon leveraged inUIPickerViewRecorder
(and later inUIDatePickerViewRecorder
).How?
Before this change, only two strategies existed, denoted by
recordSubtree: Bool
flag. For a given hierarchy, either all subviews were recorded or all could be ignored:In result, the recorder was visiting following nodes in DFS order:
With this PR, we're adding one more strategy, so changing
recordSubtree
boolean into anenum
:By using the new
.replace(subtreeNodes:)
strategy, certain node recorders (e.g.UIPickerViewRecorder
) will be able to opt-out from their subtree traversal and instead replace the subtree with its curated[Node]
information:This will enable code reuse for certain view-tree recorders, meaning:
UIViewRecorder
,UILabelRecorder
,UISwitchRecorder
,UISliderRecorder
, ...) - as we can expect any node in the root view's hierarchy;UIViewPickerRecorder
could opt-in onlyUILabelRecorder
andUIViewRecorder
- as we expect only labels and shapes in picker's subtree;Last not least, this required switching from tree-like nodes structure:
to flat array given by DFS-visit order:
The change of data structure should have no impact on the SR performance - nodes were already visited in DFS order, here we just add them to an array while visiting (instead of allocating a graph).
Review checklist
Custom CI job configuration (optional)