diff --git a/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift index e8cf64015..7c82b2e95 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift @@ -32,13 +32,12 @@ struct ContentPathObservers { mutating func notifyPathChanged(for parent: ViewResponder, changes: ContentPathChanges, transform: (old: ViewTransform, new: ViewTransform)) { let oldObservers = observers observers = [] - var failedObservers: [Observer] = [] for observer in oldObservers { var result = true guard let value = observer.value else { continue } value.contentPathDidChange(for: parent, changes: changes, transform: transform, finished: &result) guard !result else { continue } - failedObservers.append(observer) + observers.append(observer) } } } diff --git a/Tests/OpenSwiftUICoreTests/Event/ContentPathObserverTests.swift b/Tests/OpenSwiftUICoreTests/Event/ContentPathObserverTests.swift new file mode 100644 index 000000000..7ca892e79 --- /dev/null +++ b/Tests/OpenSwiftUICoreTests/Event/ContentPathObserverTests.swift @@ -0,0 +1,46 @@ +// +// ContentPathObserverTests.swift +// OpenSwiftUICoreTests + +@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore +@testable import OpenSwiftUICore +import Testing + +struct ContentPathObserverTests { + @Test + func unfinishedObserverIsRetainedUntilFinished() { + var observers = ContentPathObservers() + let observer = TestContentPathObserver() + // The test observer does not inspect its parent. Avoid constructing a + // ViewResponder, whose public initializer requires a live ViewGraph. + let parentObject: AnyObject = ResponderNode() + let parent = unsafeBitCast(parentObject, to: ViewResponder.self) + let transform = (old: ViewTransform(), new: ViewTransform()) + + observers.addObserver(observer) + observers.notifyPathChanged(for: parent, changes: [], transform: transform) + #expect(observer.callCount == 1) + + observers.notifyPathChanged(for: parent, changes: [], transform: transform) + #expect(observer.callCount == 2) + + observers.notifyPathChanged(for: parent, changes: [], transform: transform) + #expect(observer.callCount == 2) + } +} + +private final class TestContentPathObserver: ContentPathObserver { + private(set) var callCount = 0 + + func respondersDidChange(for parent: ViewResponder) {} + + func contentPathDidChange( + for parent: ViewResponder, + changes: ContentPathChanges, + transform: (old: ViewTransform, new: ViewTransform), + finished: inout Bool + ) { + callCount += 1 + finished = callCount >= 2 + } +}