From a891de37db0e0ff8718246a8972c4473e2ca03f5 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 21 May 2024 14:14:03 -0400 Subject: [PATCH] Don't store modifiers in an adjacent List (#2047) There's a 'context' field in Node that's a better fit. The problem with storing modifiers in an adjacent list is that Yoga occasionally will create a mutable copy of the layout nodes to do some layout calculation, and this mutable copy may drift from our true copy with respect to child counts. --- .../redwood/layout/uiview/UIViewFlexContainer.kt | 12 +++++------- .../commonMain/kotlin/app/cash/redwood/yoga/Node.kt | 5 +++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/redwood-layout-uiview/src/commonMain/kotlin/app/cash/redwood/layout/uiview/UIViewFlexContainer.kt b/redwood-layout-uiview/src/commonMain/kotlin/app/cash/redwood/layout/uiview/UIViewFlexContainer.kt index 341a22e8bb..a5ab5e81c3 100644 --- a/redwood-layout-uiview/src/commonMain/kotlin/app/cash/redwood/layout/uiview/UIViewFlexContainer.kt +++ b/redwood-layout-uiview/src/commonMain/kotlin/app/cash/redwood/layout/uiview/UIViewFlexContainer.kt @@ -31,10 +31,9 @@ import platform.darwin.NSInteger internal class UIViewFlexContainer( direction: FlexDirection, ) : YogaFlexContainer, ChangeListener { - private val modifiers = mutableListOf() private val yogaView: YogaUIView = YogaUIView( applyModifier = { node, index -> - node.applyModifier(modifiers[index], Density.Default) + node.applyModifier(node.context as Modifier, Density.Default) }, ) override val rootNode: Node get() = yogaView.rootNode @@ -43,19 +42,17 @@ internal class UIViewFlexContainer( override val children: UIViewChildren = UIViewChildren( container = value, insert = { view, modifier, index -> - modifiers.add(index, modifier) - yogaView.rootNode.children.add(index, view.asNode()) + yogaView.rootNode.children.add(index, view.asNode(context = modifier)) value.insertSubview(view, index.convert()) }, remove = { index, count -> - modifiers.remove(index, count) yogaView.rootNode.children.remove(index, count) Array(count) { value.typedSubviews[index].also(UIView::removeFromSuperview) } }, updateModifier = { modifier, index -> - modifiers[index] = modifier + yogaView.rootNode.children[index].context = modifier }, ) override var modifier: Modifier = Modifier @@ -82,8 +79,9 @@ internal class UIViewFlexContainer( } } -private fun UIView.asNode(): Node { +private fun UIView.asNode(context: Any?): Node { val childNode = Node() childNode.measureCallback = UIViewMeasureCallback(this) + childNode.context = context return childNode } diff --git a/redwood-yoga/src/commonMain/kotlin/app/cash/redwood/yoga/Node.kt b/redwood-yoga/src/commonMain/kotlin/app/cash/redwood/yoga/Node.kt index 395c024514..11957a2b8f 100644 --- a/redwood-yoga/src/commonMain/kotlin/app/cash/redwood/yoga/Node.kt +++ b/redwood-yoga/src/commonMain/kotlin/app/cash/redwood/yoga/Node.kt @@ -27,6 +27,11 @@ public class Node internal constructor( // Inputs public val children: MutableList = Children() + public var context: Any? + get() = native.context + set(value) { + native.context = value + } public val owner: Node? get() = native.owner?.let(::Node) public var direction: Direction