Skip to content

Commit 36e8564

Browse files
bharath2020atlassianfreak4pc
authored andcommitted
fix memory leak of receiver while using withLatestFrom operator
1 parent 98ff2ad commit 36e8564

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

Sources/Operators/WithLatestFrom.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ private extension Publishers.WithLatestFrom {
230230
}
231231

232232
func cancel() {
233+
sink?.cancelUpstream()
233234
sink = nil
234235
otherSubscription?.cancel()
235236
}

Tests/WithLatestFromTests.swift

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,32 @@ class WithLatestFromTests: XCTestCase {
9999
XCTAssertTrue(completed)
100100
}
101101

102+
func testWithResultSelectorDoesNotRetainClassBasedPublisher() {
103+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
104+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
105+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
106+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
107+
108+
var results = [String]()
109+
110+
subscription = subject1?
111+
.withLatestFrom(subject2!) { "\($0)\($1)" }
112+
.sink(receiveCompletion: { _ in },
113+
receiveValue: { results.append($0) })
114+
115+
subject1?.send(1)
116+
subject2?.send("bar")
117+
subject1?.send(2)
118+
119+
XCTAssertEqual(results, ["2bar"])
120+
121+
subscription = nil
122+
subject1 = nil
123+
subject2 = nil
124+
XCTAssertNil(weakSubject1)
125+
XCTAssertNil(weakSubject2)
126+
}
127+
102128
func testNoResultSelector() {
103129
let subject1 = PassthroughSubject<Int, Never>()
104130
let subject2 = PassthroughSubject<String, Never>()
@@ -137,6 +163,32 @@ class WithLatestFromTests: XCTestCase {
137163
XCTAssertTrue(completed)
138164
subscription.cancel()
139165
}
166+
167+
func testNoResultSelectorDoesNotRetainClassBasedPublisher() {
168+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
169+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
170+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
171+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
172+
173+
var results = [String]()
174+
175+
subscription = subject1?
176+
.withLatestFrom(subject2!)
177+
.sink(receiveCompletion: { _ in },
178+
receiveValue: { results.append($0) })
179+
180+
subject1?.send(1)
181+
subject2?.send("bar")
182+
subject1?.send(4)
183+
184+
XCTAssertEqual(results, ["bar"])
185+
186+
subscription = nil
187+
subject1 = nil
188+
subject2 = nil
189+
XCTAssertNil(weakSubject1)
190+
XCTAssertNil(weakSubject2)
191+
}
140192

141193
func testWithLatestFrom2WithResultSelector() {
142194
let subject1 = PassthroughSubject<Int, Never>()
@@ -192,6 +244,38 @@ class WithLatestFromTests: XCTestCase {
192244
subject1.send(completion: .finished)
193245
XCTAssertTrue(completed)
194246
}
247+
248+
func testWithLatestFrom2WithResultSectorDoesNotRetainPublisher() {
249+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
250+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
251+
var subject3: PassthroughSubject<Bool, Never>? = PassthroughSubject<Bool, Never>()
252+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
253+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
254+
weak var weakSubject3: PassthroughSubject<Bool, Never>? = subject3
255+
256+
var results = [String]()
257+
258+
subscription = subject1?
259+
.withLatestFrom(subject2!, subject3!) { "\($0)|\($1.0)|\($1.1)" }
260+
.sink(
261+
receiveCompletion: { _ in },
262+
receiveValue: { results.append($0) }
263+
)
264+
265+
subject2?.send("bar")
266+
subject3?.send(true)
267+
subject1?.send(10)
268+
269+
XCTAssertEqual(results, ["10|bar|true"])
270+
271+
subscription = nil
272+
subject1 = nil
273+
subject2 = nil
274+
subject3 = nil
275+
XCTAssertNil(weakSubject1)
276+
XCTAssertNil(weakSubject2)
277+
XCTAssertNil(weakSubject3)
278+
}
195279

196280
func testWithLatestFrom2WithNoResultSelector() {
197281

@@ -253,6 +337,39 @@ class WithLatestFromTests: XCTestCase {
253337
subject1.send(completion: .finished)
254338
XCTAssertTrue(completed)
255339
}
340+
341+
func testWithLatestFrom2WithNoResultSectorDoesNotRetainPublisher() {
342+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
343+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
344+
var subject3: PassthroughSubject<Bool, Never>? = PassthroughSubject<Bool, Never>()
345+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
346+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
347+
weak var weakSubject3: PassthroughSubject<Bool, Never>? = subject3
348+
349+
var results = [String]()
350+
351+
subscription = subject1?
352+
.withLatestFrom(subject2!, subject3!)
353+
.sink(
354+
receiveCompletion: { _ in },
355+
receiveValue: { results.append("\($0.0)|\($0.1)") }
356+
)
357+
358+
subject2?.send("bar")
359+
subject3?.send(true)
360+
subject1?.send(10)
361+
362+
363+
XCTAssertEqual(results, ["bar|true"])
364+
365+
subscription = nil
366+
subject1 = nil
367+
subject2 = nil
368+
subject3 = nil
369+
XCTAssertNil(weakSubject1)
370+
XCTAssertNil(weakSubject2)
371+
XCTAssertNil(weakSubject3)
372+
}
256373

257374
func testWithLatestFrom3WithResultSelector() {
258375
let subject1 = PassthroughSubject<Int, Never>()
@@ -316,6 +433,45 @@ class WithLatestFromTests: XCTestCase {
316433
subject1.send(completion: .finished)
317434
XCTAssertTrue(completed)
318435
}
436+
437+
func testWithLatestFrom3WithResultSectorDoesNotRetainPublisher() {
438+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
439+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
440+
var subject3: PassthroughSubject<Bool, Never>? = PassthroughSubject<Bool, Never>()
441+
var subject4: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
442+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
443+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
444+
weak var weakSubject3: PassthroughSubject<Bool, Never>? = subject3
445+
weak var weakSubject4: PassthroughSubject<Bool, Never>? = subject3
446+
447+
var results = [String]()
448+
449+
subscription = subject1?
450+
.withLatestFrom(subject2!, subject3!, subject4!) { "\($0)|\($1.0)|\($1.1)|\($1.2)" }
451+
.sink(
452+
receiveCompletion: { _ in },
453+
receiveValue: { results.append($0) }
454+
)
455+
456+
subject2?.send("bar")
457+
subject3?.send(true)
458+
subject4?.send(100)
459+
460+
subject1?.send(10)
461+
462+
463+
XCTAssertEqual(results, ["10|bar|true|100"])
464+
465+
subscription = nil
466+
subject1 = nil
467+
subject2 = nil
468+
subject3 = nil
469+
subject4 = nil
470+
XCTAssertNil(weakSubject1)
471+
XCTAssertNil(weakSubject2)
472+
XCTAssertNil(weakSubject3)
473+
XCTAssertNil(weakSubject4)
474+
}
319475

320476
func testWithLatestFrom3WithNoResultSelector() {
321477

@@ -386,5 +542,44 @@ class WithLatestFromTests: XCTestCase {
386542
subject1.send(completion: .finished)
387543
XCTAssertTrue(completed)
388544
}
545+
546+
func testWithLatestFrom3WithNoResultSectorDoesNotRetainPublisher() {
547+
var subject1: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
548+
var subject2: PassthroughSubject<String, Never>? = PassthroughSubject<String, Never>()
549+
var subject3: PassthroughSubject<Bool, Never>? = PassthroughSubject<Bool, Never>()
550+
var subject4: PassthroughSubject<Int, Never>? = PassthroughSubject<Int, Never>()
551+
weak var weakSubject1: PassthroughSubject<Int, Never>? = subject1
552+
weak var weakSubject2: PassthroughSubject<String, Never>? = subject2
553+
weak var weakSubject3: PassthroughSubject<Bool, Never>? = subject3
554+
weak var weakSubject4: PassthroughSubject<Bool, Never>? = subject3
555+
556+
var results = [String]()
557+
558+
subscription = subject1?
559+
.withLatestFrom(subject2!, subject3!, subject4!)
560+
.sink(
561+
receiveCompletion: { _ in },
562+
receiveValue: { results.append("\($0.0)|\($0.1)|\($0.2)") }
563+
)
564+
565+
subject2?.send("bar")
566+
subject3?.send(true)
567+
subject4?.send(100)
568+
569+
subject1?.send(10)
570+
571+
572+
XCTAssertEqual(results, ["bar|true|100"])
573+
574+
subscription = nil
575+
subject1 = nil
576+
subject2 = nil
577+
subject3 = nil
578+
subject4 = nil
579+
XCTAssertNil(weakSubject1)
580+
XCTAssertNil(weakSubject2)
581+
XCTAssertNil(weakSubject3)
582+
XCTAssertNil(weakSubject4)
583+
}
389584
}
390585
#endif

0 commit comments

Comments
 (0)