From 3f9c004095352910b948318ec32f3ae699b4bc02 Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Fri, 16 Oct 2026 18:32:12 +0800 Subject: [PATCH] Defer throwing signal work until observation --- Sources/Signal.swift | 2 +- Tests/ReactiveKitTests/SignalTests.swift | 47 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Sources/Signal.swift b/Sources/Signal.swift index fda7862..b6abfc3 100644 --- a/Sources/Signal.swift +++ b/Sources/Signal.swift @@ -219,7 +219,7 @@ extension Signal where Error == Swift.Error { /// /// - Parameter body: A throwing closure to evaluate. public init(catching body: @escaping () throws -> Element) { - self = Signal(result: Result(catching: body)) + self = Signal(evaluating: { Result(catching: body) }) } /// Create a new signal by awaiting an async closure. diff --git a/Tests/ReactiveKitTests/SignalTests.swift b/Tests/ReactiveKitTests/SignalTests.swift index 2618b1c..2cb5a48 100644 --- a/Tests/ReactiveKitTests/SignalTests.swift +++ b/Tests/ReactiveKitTests/SignalTests.swift @@ -59,6 +59,50 @@ class SignalTests: XCTestCase { XCTAssertTrue(subscriber.isFinished) } + func testCatchingDefersWorkUntilEachObservation() { + var calls = 0 + let publisher = Signal(catching: { + calls += 1 + return calls + }) + XCTAssertEqual(calls, 0) + + let first = Subscribers.Accumulator() + publisher.subscribe(first) + XCTAssertEqual(first.values, [1]) + XCTAssertTrue(first.isFinished) + + let second = Subscribers.Accumulator() + publisher.subscribe(second) + XCTAssertEqual(second.values, [2]) + XCTAssertTrue(second.isFinished) + XCTAssertEqual(calls, 2) + } + + func testCatchingPropagatesFailure() { + let publisher = Signal(catching: { throw TestError.error }) + let subscriber = Subscribers.Accumulator() + publisher.subscribe(subscriber) + XCTAssertEqual(subscriber.values, []) + XCTAssertEqual(subscriber.error as? TestError, .error) + } + + func testCatchingRetriesThrowingWork() { + var attempts = 0 + let publisher = Signal(catching: { + attempts += 1 + if attempts == 1 { + throw TestError.error + } + return 42 + }) + let subscriber = Subscribers.Accumulator() + publisher.retry(1).subscribe(subscriber) + XCTAssertEqual(subscriber.values, [42]) + XCTAssertTrue(subscriber.isFinished) + XCTAssertEqual(attempts, 2) + } + func testSequence() { let subscriber = Subscribers.Accumulator() let publisher = Signal(sequence: [1, 2, 3]) @@ -970,6 +1014,9 @@ extension SignalTests { ("testProductionAndObservation", testProductionAndObservation), ("testDisposing", testDisposing), ("testJust", testJust), + ("testCatchingDefersWorkUntilEachObservation", testCatchingDefersWorkUntilEachObservation), + ("testCatchingPropagatesFailure", testCatchingPropagatesFailure), + ("testCatchingRetriesThrowingWork", testCatchingRetriesThrowingWork), ("testSequence", testSequence), ("testCompleted", testCompleted), ("testNever", testNever),