Skip to content

Commit af1dcf0

Browse files
authored
Restore original cancellation logic (#245)
* Revert "Run swift-format" This reverts commit 6a5b8f2. * Revert "Fix iOS 14 Cancellation Crash (#244)" This reverts commit 2bf1be6. * Xcode 12 CI * Update ci.yml
1 parent 6a5b8f2 commit af1dcf0

File tree

2 files changed

+33
-88
lines changed

2 files changed

+33
-88
lines changed

Sources/ComposableArchitecture/Effects/Cancellation.swift

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -27,61 +27,35 @@ extension Effect {
2727
/// canceled before starting this new one.
2828
/// - Returns: A new effect that is capable of being canceled by an identifier.
2929
public func cancellable(id: AnyHashable, cancelInFlight: Bool = false) -> Effect {
30-
// NB: This check intends to work around bugs over different versions of Combine
31-
#if swift(>=5.3) && !os(macOS)
32-
let effect = Deferred<
33-
Publishers.PrefixUntilOutput<Publishers.HandleEvents<Self>, PassthroughSubject<Void, Never>>
34-
> {
35-
let subject = PassthroughSubject<Void, Never>()
36-
lock.sync { subjects[id, default: []].append(subject) }
37-
let cleanup = {
38-
lock.sync {
39-
subjects[id]?.removeAll(where: { $0 === subject })
40-
if subjects[id]?.isEmpty == true {
41-
subjects[id] = nil
42-
}
43-
}
44-
}
45-
return
46-
self
47-
.handleEvents(
48-
receiveCompletion: { _ in cleanup() },
49-
receiveCancel: cleanup
50-
)
51-
.prefix(untilOutputFrom: subject)
52-
}
53-
.eraseToEffect()
54-
#else
55-
let effect = Deferred { () -> Publishers.HandleEvents<PassthroughSubject<Output, Failure>> in
56-
cancellablesLock.lock()
57-
defer { cancellablesLock.unlock() }
30+
let effect = Deferred { () -> Publishers.HandleEvents<PassthroughSubject<Output, Failure>> in
31+
cancellablesLock.lock()
32+
defer { cancellablesLock.unlock() }
5833

59-
let subject = PassthroughSubject<Output, Failure>()
60-
let cancellable = self.subscribe(subject)
34+
let subject = PassthroughSubject<Output, Failure>()
35+
let cancellable = self.subscribe(subject)
6136

62-
var cancellationCancellable: AnyCancellable!
63-
cancellationCancellable = AnyCancellable {
64-
cancellablesLock.sync {
65-
subject.send(completion: .finished)
66-
cancellable.cancel()
67-
cancellationCancellables[id]?.remove(cancellationCancellable)
68-
if cancellationCancellables[id]?.isEmpty == .some(true) {
69-
cancellationCancellables[id] = nil
70-
}
37+
var cancellationCancellable: AnyCancellable!
38+
cancellationCancellable = AnyCancellable {
39+
cancellablesLock.sync {
40+
subject.send(completion: .finished)
41+
cancellable.cancel()
42+
cancellationCancellables[id]?.remove(cancellationCancellable)
43+
if cancellationCancellables[id]?.isEmpty == .some(true) {
44+
cancellationCancellables[id] = nil
7145
}
7246
}
47+
}
7348

74-
cancellationCancellables[id, default: []].insert(
75-
cancellationCancellable
76-
)
49+
cancellationCancellables[id, default: []].insert(
50+
cancellationCancellable
51+
)
7752

78-
return subject.handleEvents(
79-
receiveCompletion: { _ in cancellationCancellable.cancel() },
80-
receiveCancel: cancellationCancellable.cancel
81-
)
82-
}
83-
.eraseToEffect()
84-
#endif
53+
return subject.handleEvents(
54+
receiveCompletion: { _ in cancellationCancellable.cancel() },
55+
receiveCancel: cancellationCancellable.cancel
56+
)
57+
}
58+
.eraseToEffect()
8559

8660
return cancelInFlight ? .concatenate(.cancel(id: id), effect) : effect
8761
}
@@ -92,26 +66,13 @@ extension Effect {
9266
/// - Returns: A new effect that will cancel any currently in-flight effect with the given
9367
/// identifier.
9468
public static func cancel(id: AnyHashable) -> Effect {
95-
#if swift(>=5.3) && !os(macOS)
96-
return .fireAndForget {
97-
lock.sync {
98-
subjects[id]?.forEach { $0.send(()) }
99-
}
100-
}
101-
#else
102-
return .fireAndForget {
103-
cancellablesLock.sync {
104-
cancellationCancellables[id]?.forEach { $0.cancel() }
105-
}
69+
return .fireAndForget {
70+
cancellablesLock.sync {
71+
cancellationCancellables[id]?.forEach { $0.cancel() }
10672
}
107-
#endif
73+
}
10874
}
10975
}
11076

111-
#if swift(>=5.3) && !os(macOS)
112-
var subjects: [AnyHashable: [PassthroughSubject<Void, Never>]] = [:]
113-
let lock = NSRecursiveLock()
114-
#else
115-
var cancellationCancellables: [AnyHashable: Set<AnyCancellable>] = [:]
116-
let cancellablesLock = NSRecursiveLock()
117-
#endif
77+
var cancellationCancellables: [AnyHashable: Set<AnyCancellable>] = [:]
78+
let cancellablesLock = NSRecursiveLock()

Tests/ComposableArchitectureTests/EffectCancellationTests.swift

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,7 @@ final class EffectCancellationTests: XCTestCase {
116116
.sink(receiveValue: { _ in })
117117
.store(in: &self.cancellables)
118118

119-
#if swift(>=5.3) && !os(macOS)
120-
XCTAssertTrue(subjects.isEmpty)
121-
#else
122-
XCTAssertTrue(cancellationCancellables.isEmpty)
123-
#endif
119+
XCTAssertEqual([:], cancellationCancellables)
124120
}
125121

126122
func testCancellablesCleanUp_OnCancel() {
@@ -136,11 +132,7 @@ final class EffectCancellationTests: XCTestCase {
136132
.sink(receiveValue: { _ in })
137133
.store(in: &self.cancellables)
138134

139-
#if swift(>=5.3) && !os(macOS)
140-
XCTAssertTrue(subjects.isEmpty)
141-
#else
142-
XCTAssertTrue(cancellationCancellables.isEmpty)
143-
#endif
135+
XCTAssertEqual([:], cancellationCancellables)
144136
}
145137

146138
func testDoubleCancellation() {
@@ -230,11 +222,7 @@ final class EffectCancellationTests: XCTestCase {
230222
.store(in: &self.cancellables)
231223
self.wait(for: [expectation], timeout: 999)
232224

233-
#if swift(>=5.3) && !os(macOS)
234-
XCTAssertTrue(subjects.isEmpty)
235-
#else
236-
XCTAssertTrue(cancellationCancellables.isEmpty)
237-
#endif
225+
XCTAssertTrue(cancellationCancellables.isEmpty)
238226
}
239227

240228
func testNestedCancels() {
@@ -252,11 +240,7 @@ final class EffectCancellationTests: XCTestCase {
252240

253241
cancellables.removeAll()
254242

255-
#if swift(>=5.3) && !os(macOS)
256-
XCTAssertTrue(subjects.isEmpty)
257-
#else
258-
XCTAssertTrue(cancellationCancellables.isEmpty)
259-
#endif
243+
XCTAssertEqual([:], cancellationCancellables)
260244
}
261245

262246
func testSharedId() {

0 commit comments

Comments
 (0)