Skip to content

Commit 16adb2e

Browse files
PoC: Noncopyable DisposeBag
1 parent 7570d44 commit 16adb2e

File tree

7 files changed

+55
-42
lines changed

7 files changed

+55
-42
lines changed

RxSwift/Disposables/DisposeBag.swift

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extension Disposable {
1010
/// Adds `self` to `bag`
1111
///
1212
/// - parameter bag: `DisposeBag` to add `self` to.
13-
public func disposed(by bag: DisposeBag) {
13+
public func disposed(by bag: inout DisposeBag) {
1414
bag.insert(self)
1515
}
1616
}
@@ -27,27 +27,39 @@ or create a new one in its place.
2727

2828
In case explicit disposal is necessary, there is also `CompositeDisposable`.
2929
*/
30-
public final class DisposeBag: DisposeBase {
31-
32-
private var lock = SpinLock()
33-
34-
// state
35-
private var disposables = [Disposable]()
36-
private var isDisposed = false
37-
30+
public struct DisposeBag: ~Copyable {
31+
private let implementation: _DisposeBag
32+
3833
/// Constructs new empty dispose bag.
39-
public override init() {
40-
super.init()
34+
public init() {
35+
self.implementation = _DisposeBag()
4136
}
4237

4338
/// Adds `disposable` to be disposed when dispose bag is being deinited.
4439
///
4540
/// - parameter disposable: Disposable to add.
41+
public /*mutating*/ func insert(_ disposable: Disposable) {
42+
implementation._insert(disposable)?.dispose()
43+
}
44+
}
45+
46+
private final class _DisposeBag: DisposeBase {
47+
48+
fileprivate var lock = SpinLock()
49+
50+
// state
51+
fileprivate var disposables = [Disposable]()
52+
fileprivate private(set) var isDisposed = false
53+
54+
public override init() {
55+
super.init()
56+
}
57+
4658
public func insert(_ disposable: Disposable) {
4759
self._insert(disposable)?.dispose()
4860
}
4961

50-
private func _insert(_ disposable: Disposable) -> Disposable? {
62+
fileprivate func _insert(_ disposable: Disposable) -> Disposable? {
5163
self.lock.performLocked {
5264
if self.isDisposed {
5365
return disposable
@@ -86,21 +98,21 @@ public final class DisposeBag: DisposeBase {
8698

8799
extension DisposeBag {
88100
/// Convenience init allows a list of disposables to be gathered for disposal.
89-
public convenience init(disposing disposables: Disposable...) {
90-
self.init()
91-
self.disposables += disposables
101+
public init(disposing disposables: Disposable...) {
102+
self = DisposeBag()
103+
self.implementation.disposables += disposables
92104
}
93105

94106
/// Convenience init which utilizes a function builder to let you pass in a list of
95107
/// disposables to make a DisposeBag of.
96-
public convenience init(@DisposableBuilder builder: () -> [Disposable]) {
108+
public init(@DisposableBuilder builder: () -> [Disposable]) {
97109
self.init(disposing: builder())
98110
}
99111

100112
/// Convenience init allows an array of disposables to be gathered for disposal.
101-
public convenience init(disposing disposables: [Disposable]) {
113+
public init(disposing disposables: [Disposable]) {
102114
self.init()
103-
self.disposables += disposables
115+
self.implementation.disposables += disposables
104116
}
105117

106118
/// Convenience function allows a list of disposables to be gathered for disposal.
@@ -115,11 +127,11 @@ extension DisposeBag {
115127

116128
/// Convenience function allows an array of disposables to be gathered for disposal.
117129
public func insert(_ disposables: [Disposable]) {
118-
self.lock.performLocked {
119-
if self.isDisposed {
130+
self.implementation.lock.performLocked {
131+
if self.implementation.isDisposed {
120132
disposables.forEach { $0.dispose() }
121133
} else {
122-
self.disposables += disposables
134+
self.implementation.disposables += disposables
123135
}
124136
}
125137
}

Tests/RxCocoaTests/DelegateProxyTest.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,8 +786,9 @@ extension DelegateProxyTest {
786786
let collection = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
787787
let mockDelegate = MockDelegate()
788788
collection.delegate = mockDelegate
789-
collection.rx.contentOffset.subscribe().disposed(by: DisposeBag())
790-
789+
var disposeBag = DisposeBag()
790+
collection.rx.contentOffset.subscribe().disposed(by: &disposeBag)
791+
791792
let selector = #selector(getter: MockDelegate.demoText)
792793
if ((collection.delegate?.responds(to: selector)) != nil) {
793794
let performResult = collection.delegate?.perform(selector)?.takeRetainedValue()

Tests/RxCocoaTests/Driver+Test.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,19 @@ extension DriverTest {
269269

270270
relay.asDriver()
271271
.drive(observer)
272-
.disposed(by: disposeBag)
272+
.disposed(by: &disposeBag)
273273

274274
prepareSampleDriver(with: "first")
275275
.drive(relay)
276-
.disposed(by: disposeBag)
276+
.disposed(by: &disposeBag)
277277

278278
prepareSampleDriver(with: "second")
279279
.drive(relay)
280-
.disposed(by: disposeBag)
280+
.disposed(by: &disposeBag)
281281

282282
Observable.just("third")
283283
.bind(to: relay)
284-
.disposed(by: disposeBag)
284+
.disposed(by: &disposeBag)
285285

286286
disposeBag = DisposeBag()
287287

Tests/RxCocoaTests/KVOObservableTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class Parent : NSObject {
3939

4040
self.rx.observe(String.self, "val", options: [.initial, .new], retainSelf: false)
4141
.subscribe(onNext: callback)
42-
.disposed(by: disposeBag)
42+
.disposed(by: &disposeBag)
4343
}
4444

4545
deinit {
@@ -48,13 +48,13 @@ final class Parent : NSObject {
4848
}
4949

5050
final class Child : NSObject {
51-
let disposeBag = DisposeBag()
51+
var disposeBag = DisposeBag()
5252

5353
init(parent: ParentWithChild, callback: @escaping (String?) -> Void) {
5454
super.init()
5555
parent.rx.observe(String.self, "val", options: [.initial, .new], retainSelf: false)
5656
.subscribe(onNext: callback)
57-
.disposed(by: disposeBag)
57+
.disposed(by: &disposeBag)
5858
}
5959

6060
deinit {

Tests/RxCocoaTests/RxTest+Controls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ extension RxTest {
103103
func ensureControlObserverHasWeakReference<C, T>(file: StaticString = #file, line: UInt = #line, _ createControl: @autoclosure() -> (C), _ observerSelector: (C) -> AnyObserver<T>, _ observableSelector: () -> (Observable<T>)) where C: NSObject {
104104
var deallocated = false
105105

106-
let disposeBag = DisposeBag()
106+
var disposeBag = DisposeBag()
107107

108108
autoreleasepool {
109109
let control = createControl()
110110
let propertyObserver = observerSelector(control)
111111
let observable = observableSelector()
112112

113-
observable.bind(to: propertyObserver).disposed(by: disposeBag)
113+
observable.bind(to: propertyObserver).disposed(by: &disposeBag)
114114

115115
_ = (control as NSObject).rx.deallocated.subscribe(onNext: { _ in
116116
deallocated = true

Tests/RxCocoaTests/SentMessageTest.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -645,11 +645,11 @@ extension SentMessageTest {
645645
func testFailsInCaseObjectIsAlreadyBeingInterceptedWithKVO_sentMessage() {
646646
let target = SentMessageTest_shared()
647647

648-
let disposeBag = DisposeBag()
648+
var disposeBag = DisposeBag()
649649
target.rx.observe(NSArray.self, "messages")
650650
.subscribe(onNext: { _ in
651651
})
652-
.disposed(by: disposeBag)
652+
.disposed(by: &disposeBag)
653653

654654
do {
655655
_ = try target.rx.sentMessage(#selector(SentMessageTestBase_shared.justCalledBool(toSay:)))
@@ -672,11 +672,11 @@ extension SentMessageTest {
672672
func testFailsInCaseObjectIsAlreadyBeingInterceptedWithKVO_methodInvoked() {
673673
let target = SentMessageTest_shared()
674674

675-
let disposeBag = DisposeBag()
675+
var disposeBag = DisposeBag()
676676
target.rx.observe(NSArray.self, "messages")
677677
.subscribe(onNext: { _ in
678678
})
679-
.disposed(by: disposeBag)
679+
.disposed(by: &disposeBag)
680680

681681
do {
682682
_ = try target.rx.methodInvoked(#selector(SentMessageTestBase_shared.justCalledBool(toSay:)))
@@ -863,7 +863,7 @@ extension SentMessageTest {
863863
var messages: Observable<MethodParameters>!
864864
var recordedMessages = [MethodParameters]()
865865
var completed = false
866-
let disposeBag = DisposeBag()
866+
var disposeBag = DisposeBag()
867867

868868
var stages: [MessageProcessingStage] = []
869869

@@ -883,7 +883,7 @@ extension SentMessageTest {
883883
stages.append(.sentMessage)
884884
}, onCompleted: {
885885
completed = true
886-
}).disposed(by: disposeBag)
886+
}).disposed(by: &disposeBag)
887887

888888
target.justCalledBool(toSay: true)
889889
}
@@ -897,7 +897,7 @@ extension SentMessageTest {
897897
var messages: Observable<MethodParameters>!
898898
var recordedMessages = [MethodParameters]()
899899
var completed = false
900-
let disposeBag = DisposeBag()
900+
var disposeBag = DisposeBag()
901901

902902
var stages: [MessageProcessingStage] = []
903903

@@ -917,7 +917,7 @@ extension SentMessageTest {
917917
stages.append(.methodInvoked)
918918
}, onCompleted: {
919919
completed = true
920-
}).disposed(by: disposeBag)
920+
}).disposed(by: &disposeBag)
921921

922922
target.justCalledBool(toSay: true)
923923
}

Tests/RxSwiftTests/Anomalies.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ extension AnomaliesTest {
100100
}
101101

102102
func test1344(){
103-
let disposeBag = DisposeBag()
103+
var disposeBag = DisposeBag()
104104
let foo = Observable<Int>.create({ observer in
105105
observer.on(.next(1))
106106
Thread.sleep(forTimeInterval: 0.1)
@@ -119,7 +119,7 @@ extension AnomaliesTest {
119119

120120
Observable.merge(foo, .just([42]))
121121
.subscribe()
122-
.disposed(by: disposeBag)
122+
.disposed(by: &disposeBag)
123123
}
124124

125125
func testSeparationBetweenOnAndSubscriptionLocks() {

0 commit comments

Comments
 (0)