Skip to content

Commit

Permalink
fix further cases of incorrect reuses
Browse files Browse the repository at this point in the history
  • Loading branch information
lkzhao committed Mar 14, 2024
1 parent 711ced1 commit f7d4c5c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
6 changes: 6 additions & 0 deletions Sources/UIComponent/Core/Model/RenderNode/AnyRenderNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public struct AnyRenderNode: RenderNode {
public var reuseStrategy: ReuseStrategy {
erasing.reuseStrategy
}
public var defaultReuseKey: String {
"AnyRenderNode<\(erasing.defaultReuseKey)>"
}
public var size: CGSize {
erasing.size
}
Expand Down Expand Up @@ -71,6 +74,9 @@ public struct AnyRenderNodeOfView<View: UIView>: RenderNode {
public var reuseStrategy: ReuseStrategy {
erasing.reuseStrategy
}
public var defaultReuseKey: String {
"AnyRenderNodeOfView<\(erasing.defaultReuseKey)>"
}
public var size: CGSize {
erasing.size
}
Expand Down
9 changes: 7 additions & 2 deletions Sources/UIComponent/Core/Model/RenderNode/RenderNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public protocol RenderNode<View> {
/// The strategy to use when reusing views.
var reuseStrategy: ReuseStrategy { get }

/// The default reuse key for the render node. This key will be used when reuseStrategy is set to .automatic.
/// This will also be used as fallbackId for structured identity when id is not set.
var defaultReuseKey: String { get }

/// The size of the render node.
var size: CGSize { get }

Expand Down Expand Up @@ -108,6 +112,7 @@ extension RenderNode {
public var id: String? { nil }
public var animator: Animator? { nil }
public var reuseStrategy: ReuseStrategy { .automatic }
public var defaultReuseKey: String { "\(type(of: self))" }
public var shouldRenderView: Bool { children.isEmpty }

public func makeView() -> View {
Expand All @@ -132,7 +137,7 @@ extension RenderNode {
public func defaultVisibleRenderablesImplementation(in frame: CGRect) -> [Renderable] {
var result = [Renderable]()
if shouldRenderView, frame.intersects(CGRect(origin: .zero, size: size)) {
result.append(Renderable(frame: CGRect(origin: .zero, size: size), renderNode: self, fallbackId: "\(type(of: self))"))
result.append(Renderable(frame: CGRect(origin: .zero, size: size), renderNode: self, fallbackId: defaultReuseKey))
}
let indexes = visibleIndexes(in: frame)
for i in indexes {
Expand All @@ -155,7 +160,7 @@ extension RenderNode {
internal func _makeView() -> UIView {
switch reuseStrategy {
case .automatic:
return ReuseManager.shared.dequeue(identifier: "\(type(of: self))", makeView())
return ReuseManager.shared.dequeue(identifier: defaultReuseKey, makeView())
case .noReuse:
return makeView()
case .key(let key):
Expand Down
20 changes: 20 additions & 0 deletions Tests/UIComponentTests/ReuseTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import XCTest

@testable import UIComponent
import UIKit

final class ReuseTests: XCTestCase {
var componentView: ComponentView!
Expand Down Expand Up @@ -151,6 +152,25 @@ final class ReuseTests: XCTestCase {
XCTAssertNotEqual(existingLabel, newLabel)
}

func testNoReuseWithDifferentAttributesAndAnyComponentOfView() {
componentView.component = Text("1").textColor(.red).eraseToAnyComponentOfView()
componentView.reloadData()
XCTAssertEqual(componentView.subviews.count, 1)
let existingLabel = componentView.subviews.first as? UILabel
XCTAssertNotNil(existingLabel)
XCTAssertEqual(existingLabel?.text, "1")
XCTAssertEqual(existingLabel?.textColor, .red)
componentView.component = Text("2").eraseToAnyComponentOfView()
componentView.reloadData()
XCTAssertEqual(componentView.subviews.count, 1)
let newLabel = componentView.subviews.first as? UILabel
XCTAssertNotNil(newLabel)
XCTAssertEqual(newLabel?.text, "2")

// the UILabel should not be reused
XCTAssertNotEqual(existingLabel, newLabel)
}

func testNoReuseWithSameAttributes() {
componentView.component = Text("1").reuseStrategy(.noReuse).textColor(.red).id("1")
componentView.reloadData()
Expand Down

0 comments on commit f7d4c5c

Please sign in to comment.