From 4303e05089501cb0d8d3a67d4a68106573fd3771 Mon Sep 17 00:00:00 2001 From: heoblitz Date: Thu, 3 Sep 2026 18:42:36 +0900 Subject: [PATCH 1/5] Fix Observable subscribe(with:) error handling --- RxSwift/ObservableType+Extensions.swift | 8 +++-- .../ObservableType+SubscriptionTests.swift | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/RxSwift/ObservableType+Extensions.swift b/RxSwift/ObservableType+Extensions.swift index d834d2031..0398154e5 100644 --- a/RxSwift/ObservableType+Extensions.swift +++ b/RxSwift/ObservableType+Extensions.swift @@ -51,9 +51,11 @@ public extension ObservableType { guard let object else { return } onNext?(object, $0) }, - onError: { [weak object] in - guard let object else { return } - onError?(object, $0) + onError: onError.map { onError in + { [weak object] in + guard let object else { return } + onError(object, $0) + } }, onCompleted: { [weak object] in guard let object else { return } diff --git a/Tests/RxSwiftTests/ObservableType+SubscriptionTests.swift b/Tests/RxSwiftTests/ObservableType+SubscriptionTests.swift index fef3c61bf..81a1908a1 100644 --- a/Tests/RxSwiftTests/ObservableType+SubscriptionTests.swift +++ b/Tests/RxSwiftTests/ObservableType+SubscriptionTests.swift @@ -34,8 +34,38 @@ extension ObservableSubscriptionTest { XCTAssertEqual(loggedErrors, [testError]) } + func testDefaultErrorHandlerWithObject() { + var loggedErrors = [TestError]() + var handledErrors = [TestError]() + let originalErrorHandler = Hooks.defaultErrorHandler + defer { Hooks.defaultErrorHandler = originalErrorHandler } + + Hooks.defaultErrorHandler = { _, error in + loggedErrors.append(error as! TestError) + } + + _ = Observable.error(testError).subscribe(with: self, onError: { _, error in + handledErrors.append(error as! TestError) + }) + + XCTAssertEqual(handledErrors, [testError]) + XCTAssertEqual(loggedErrors, []) + + _ = Observable.error(testError).subscribe(with: self) + + XCTAssertEqual(loggedErrors, [testError]) + } + func testCustomCaptureSubscriptionCallstack() { var resultCallstack = [String]() + let originalErrorHandler = Hooks.defaultErrorHandler + let originalCaptureSubscriptionCallstack = Hooks.customCaptureSubscriptionCallstack + let originalRecordCallStackOnError = Hooks.recordCallStackOnError + defer { + Hooks.defaultErrorHandler = originalErrorHandler + Hooks.customCaptureSubscriptionCallstack = originalCaptureSubscriptionCallstack + Hooks.recordCallStackOnError = originalRecordCallStackOnError + } Hooks.defaultErrorHandler = { callstack, _ in resultCallstack = callstack From aaf3368e4df32fb70893a5d74a4e3a674f9163e1 Mon Sep 17 00:00:00 2001 From: heoblitz Date: Thu, 3 Sep 2026 18:42:41 +0900 Subject: [PATCH 2/5] Fix Single subscribe(with:) error handling --- RxSwift/Traits/PrimitiveSequence/Single.swift | 8 ++++--- Tests/RxSwiftTests/SingleTest.swift | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/RxSwift/Traits/PrimitiveSequence/Single.swift b/RxSwift/Traits/PrimitiveSequence/Single.swift index 6bc9201be..e479217bb 100644 --- a/RxSwift/Traits/PrimitiveSequence/Single.swift +++ b/RxSwift/Traits/PrimitiveSequence/Single.swift @@ -108,9 +108,11 @@ public extension PrimitiveSequenceType where Trait == SingleTrait { guard let object else { return } onSuccess?(object, $0) }, - onFailure: { [weak object] in - guard let object else { return } - onFailure?(object, $0) + onFailure: onFailure.map { onFailure in + { [weak object] in + guard let object else { return } + onFailure(object, $0) + } }, onDisposed: { [weak object] in guard let object else { return } diff --git a/Tests/RxSwiftTests/SingleTest.swift b/Tests/RxSwiftTests/SingleTest.swift index e8abd041d..bf53dd669 100644 --- a/Tests/RxSwiftTests/SingleTest.swift +++ b/Tests/RxSwiftTests/SingleTest.swift @@ -780,4 +780,26 @@ extension SingleTest { _ = Single.error(testError).subscribe() XCTAssertEqual(loggedErrors, [testError]) } + + func testDefaultErrorHandlerWithObject() { + var loggedErrors = [TestError]() + var handledErrors = [TestError]() + let originalErrorHandler = Hooks.defaultErrorHandler + defer { Hooks.defaultErrorHandler = originalErrorHandler } + + Hooks.defaultErrorHandler = { _, error in + loggedErrors.append(error as! TestError) + } + + _ = Single.error(testError).subscribe(with: self, onFailure: { _, error in + handledErrors.append(error as! TestError) + }) + + XCTAssertEqual(handledErrors, [testError]) + XCTAssertEqual(loggedErrors, []) + + _ = Single.error(testError).subscribe(with: self) + + XCTAssertEqual(loggedErrors, [testError]) + } } From 07523833c01f1e8c32fb20b2302f055432ba4d51 Mon Sep 17 00:00:00 2001 From: heoblitz Date: Thu, 3 Sep 2026 18:42:47 +0900 Subject: [PATCH 3/5] Fix Maybe subscribe(with:) error handling --- RxSwift/Traits/PrimitiveSequence/Maybe.swift | 8 ++++--- Tests/RxSwiftTests/MaybeTest.swift | 22 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/RxSwift/Traits/PrimitiveSequence/Maybe.swift b/RxSwift/Traits/PrimitiveSequence/Maybe.swift index 81f739142..100df8662 100644 --- a/RxSwift/Traits/PrimitiveSequence/Maybe.swift +++ b/RxSwift/Traits/PrimitiveSequence/Maybe.swift @@ -104,9 +104,11 @@ public extension PrimitiveSequenceType where Trait == MaybeTrait { guard let object else { return } onSuccess?(object, $0) }, - onError: { [weak object] in - guard let object else { return } - onError?(object, $0) + onError: onError.map { onError in + { [weak object] in + guard let object else { return } + onError(object, $0) + } }, onCompleted: { [weak object] in guard let object else { return } diff --git a/Tests/RxSwiftTests/MaybeTest.swift b/Tests/RxSwiftTests/MaybeTest.swift index b7f240171..e8f3a6bd0 100644 --- a/Tests/RxSwiftTests/MaybeTest.swift +++ b/Tests/RxSwiftTests/MaybeTest.swift @@ -774,4 +774,26 @@ extension MaybeTest { _ = Maybe.error(testError).subscribe() XCTAssertEqual(loggedErrors, [testError]) } + + func testDefaultErrorHandlerWithObject() { + var loggedErrors = [TestError]() + var handledErrors = [TestError]() + let originalErrorHandler = Hooks.defaultErrorHandler + defer { Hooks.defaultErrorHandler = originalErrorHandler } + + Hooks.defaultErrorHandler = { _, error in + loggedErrors.append(error as! TestError) + } + + _ = Maybe.error(testError).subscribe(with: self, onError: { _, error in + handledErrors.append(error as! TestError) + }) + + XCTAssertEqual(handledErrors, [testError]) + XCTAssertEqual(loggedErrors, []) + + _ = Maybe.error(testError).subscribe(with: self) + + XCTAssertEqual(loggedErrors, [testError]) + } } From 7eff58b76c4f7c3e1f164d2051f92f107cc9664d Mon Sep 17 00:00:00 2001 From: heoblitz Date: Thu, 3 Sep 2026 18:42:52 +0900 Subject: [PATCH 4/5] Fix Completable subscribe(with:) error handling --- .../PrimitiveSequence/Completable.swift | 8 ++++--- Tests/RxSwiftTests/CompletableTest.swift | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/RxSwift/Traits/PrimitiveSequence/Completable.swift b/RxSwift/Traits/PrimitiveSequence/Completable.swift index 6a1abd471..d63b45e87 100644 --- a/RxSwift/Traits/PrimitiveSequence/Completable.swift +++ b/RxSwift/Traits/PrimitiveSequence/Completable.swift @@ -95,9 +95,11 @@ public extension PrimitiveSequenceType where Trait == CompletableTrait, Element onCompleted: { [weak object] in guard let object else { return } onCompleted?(object) - }, onError: { [weak object] in - guard let object else { return } - onError?(object, $0) + }, onError: onError.map { onError in + { [weak object] in + guard let object else { return } + onError(object, $0) + } }, onDisposed: { [weak object] in guard let object else { return } onDisposed?(object) diff --git a/Tests/RxSwiftTests/CompletableTest.swift b/Tests/RxSwiftTests/CompletableTest.swift index 0ddfe5044..92403e95c 100644 --- a/Tests/RxSwiftTests/CompletableTest.swift +++ b/Tests/RxSwiftTests/CompletableTest.swift @@ -601,6 +601,28 @@ extension CompletableTest { _ = Completable.error(testError).subscribe() XCTAssertEqual(loggedErrors, [testError]) } + + func testDefaultErrorHandlerWithObject() { + var loggedErrors = [TestError]() + var handledErrors = [TestError]() + let originalErrorHandler = Hooks.defaultErrorHandler + defer { Hooks.defaultErrorHandler = originalErrorHandler } + + Hooks.defaultErrorHandler = { _, error in + loggedErrors.append(error as! TestError) + } + + _ = Completable.error(testError).subscribe(with: self, onError: { _, error in + handledErrors.append(error as! TestError) + }) + + XCTAssertEqual(handledErrors, [testError]) + XCTAssertEqual(loggedErrors, []) + + _ = Completable.error(testError).subscribe(with: self) + + XCTAssertEqual(loggedErrors, [testError]) + } } public func == (_: Never, _: Never) -> Bool {} From 1db231a799af36b633fff72fe2cf96df7fab828d Mon Sep 17 00:00:00 2001 From: heoblitz Date: Thu, 3 Sep 2026 19:41:17 +0900 Subject: [PATCH 5/5] Update SPM test manifest --- Sources/AllTestz/main.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/AllTestz/main.swift b/Sources/AllTestz/main.swift index b136b21b3..d2fad5f6e 100644 --- a/Sources/AllTestz/main.swift +++ b/Sources/AllTestz/main.swift @@ -179,6 +179,7 @@ final class CompletableTest_ : CompletableTest, RxTestCase { ("test_zip_array", CompletableTest.test_zip_array), ("test_zip_variadic", CompletableTest.test_zip_variadic), ("testDefaultErrorHandler", CompletableTest.testDefaultErrorHandler), + ("testDefaultErrorHandlerWithObject", CompletableTest.testDefaultErrorHandlerWithObject), ] } } @@ -436,6 +437,7 @@ final class MaybeTest_ : MaybeTest, RxTestCase { ("test_zip_tuple", MaybeTest.test_zip_tuple), ("test_zip_resultSelector", MaybeTest.test_zip_resultSelector), ("testDefaultErrorHandler", MaybeTest.testDefaultErrorHandler), + ("testDefaultErrorHandlerWithObject", MaybeTest.testDefaultErrorHandlerWithObject), ("testZip2_selector", MaybeTest.testZip2_selector), ("testZip2_tuple", MaybeTest.testZip2_tuple), ("testZip3_selector", MaybeTest.testZip3_selector), @@ -1496,6 +1498,7 @@ final class ObservableSubscriptionTest_ : ObservableSubscriptionTest, RxTestCase static var allTests: [(String, (ObservableSubscriptionTest_) -> () -> Void)] { return [ ("testDefaultErrorHandler", ObservableSubscriptionTest.testDefaultErrorHandler), + ("testDefaultErrorHandlerWithObject", ObservableSubscriptionTest.testDefaultErrorHandlerWithObject), ("testCustomCaptureSubscriptionCallstack", ObservableSubscriptionTest.testCustomCaptureSubscriptionCallstack), ] } } @@ -2175,6 +2178,7 @@ final class SingleTest_ : SingleTest, RxTestCase { ("testZipCollection_tuple", SingleTest.testZipCollection_tuple), ("testZipCollection_tuple_when_empty", SingleTest.testZipCollection_tuple_when_empty), ("testDefaultErrorHandler", SingleTest.testDefaultErrorHandler), + ("testDefaultErrorHandlerWithObject", SingleTest.testDefaultErrorHandlerWithObject), ] } }