From b782c844e8f7352ba882ca36c464e582735b97e7 Mon Sep 17 00:00:00 2001 From: Kirill Yakimovich Date: Thu, 4 Dec 2025 11:17:54 -0800 Subject: [PATCH] Fix Swift 6.2 weak mutability warning in Binder --- RxSwift/Binder.swift | 6 +-- Tests/RxSwiftTests/Binder+Tests.swift | 63 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/RxSwift/Binder.swift b/RxSwift/Binder.swift index 1aae09592a..51707c3839 100644 --- a/RxSwift/Binder.swift +++ b/RxSwift/Binder.swift @@ -26,13 +26,11 @@ public struct Binder: ObserverType { /// - parameter scheduler: Scheduler used to bind the events. /// - parameter binding: Binding logic. public init(_ target: Target, scheduler: ImmediateSchedulerType = MainScheduler(), binding: @escaping (Target, Value) -> Void) { - weak var weakTarget = target - - self.binding = { event in + self.binding = { [weak target] event in switch event { case .next(let element): _ = scheduler.schedule(element) { element in - if let target = weakTarget { + if let target = target { binding(target, element) } return Disposables.create() diff --git a/Tests/RxSwiftTests/Binder+Tests.swift b/Tests/RxSwiftTests/Binder+Tests.swift index 18b5e27ce6..35ad2e21c7 100644 --- a/Tests/RxSwiftTests/Binder+Tests.swift +++ b/Tests/RxSwiftTests/Binder+Tests.swift @@ -44,4 +44,67 @@ extension BinderTests { XCTAssertNil(e) } } + + func testBinderDoesNotRetainTarget() { + var target: NSObject? = NSObject() +#if swift(>=6.2) + weak let weakTarget = target +#else + weak var weakTarget = target +#endif + + _ = Binder(target!) { (_, _: Int) in } + + target = nil + + XCTAssertNil(weakTarget) + } + + func testBindingDoesNotExecuteAfterTargetDeallocated() { + var target: NSObject? = NSObject() + var bindingExecuted = false + + let binder = Binder(target!) { (_, _: Int) in + bindingExecuted = true + } + + target = nil + binder.on(.next(1)) + + RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1)) + + XCTAssertFalse(bindingExecuted) + } + + func testBindingReceivesCorrectValue() { + let expectation = self.expectation(description: "binding executed") + let target = NSObject() + var receivedValue: Int? + + let binder = Binder(target) { (_, value: Int) in + receivedValue = value + expectation.fulfill() + } + + binder.on(.next(42)) + + waitForExpectations(timeout: 1.0) + XCTAssertEqual(receivedValue, 42) + } + + func testBindingReceivesCorrectTarget() { + let expectation = self.expectation(description: "binding executed") + let target = NSObject() + var receivedTarget: NSObject? + + let binder = Binder(target) { (t, _: Int) in + receivedTarget = t + expectation.fulfill() + } + + binder.on(.next(1)) + + waitForExpectations(timeout: 1.0) + XCTAssertTrue(receivedTarget === target) + } }