From 980726b096d810ed6b1c77826c22c2c6ec9465c3 Mon Sep 17 00:00:00 2001 From: Subeom Choi Date: Tue, 16 Apr 2024 17:30:38 +0900 Subject: [PATCH] fix: solve memory issue of cancelBlock --- .../Contract/Chain/ContractCatch.swift | 4 +- .../Contract/Chain/ContractFilter.swift | 16 +- .../Contract/Chain/ContractFinally.swift | 2 +- .../Contract/Chain/ContractRecover.swift | 16 +- .../Contract/Chain/ContractThen.swift | 16 +- .../Promise/Attribute/PromiseConvert.swift | 14 +- .../Promise/Attribute/PromiseDelay.swift | 2 +- .../Promise/Attribute/PromiseTimeout.swift | 2 +- .../Promise/Chain/PromiseCatch.swift | 4 +- .../Promise/Chain/PromiseFinally.swift | 2 +- .../Promise/Chain/PromiseRecover.swift | 16 +- .../Promise/Chain/PromiseThen.swift | 16 +- .../Promise/Composition/PromiseAll.swift | 446 +++++++----------- .../Promise/Composition/PromiseRace.swift | 2 +- Source/Concurrency/Promise/Promise.swift | 10 +- .../Promise/Attribute/PromiseDelayTest.swift | 8 +- .../Promise/Chain/PromiseCatchTest.swift | 6 +- .../Promise/Chain/PromiseFinallyTest.swift | 6 +- .../Promise/Chain/PromiseRecoverTest.swift | 6 +- .../Promise/Chain/PromiseThenTest.swift | 6 +- 20 files changed, 255 insertions(+), 345 deletions(-) diff --git a/Source/Concurrency/Contract/Chain/ContractCatch.swift b/Source/Concurrency/Contract/Chain/ContractCatch.swift index 88ae8da..446a340 100644 --- a/Source/Concurrency/Contract/Chain/ContractCatch.swift +++ b/Source/Concurrency/Contract/Chain/ContractCatch.swift @@ -29,7 +29,7 @@ extension Contract { contract.reject(error) } }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -51,7 +51,7 @@ extension Contract { block(error) contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract diff --git a/Source/Concurrency/Contract/Chain/ContractFilter.swift b/Source/Concurrency/Contract/Chain/ContractFilter.swift index 39ca5d0..436b1c9 100644 --- a/Source/Concurrency/Contract/Chain/ContractFilter.swift +++ b/Source/Concurrency/Contract/Chain/ContractFilter.swift @@ -22,7 +22,7 @@ extension Contract { if block(value) { contract.resolve(value) } }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -43,7 +43,7 @@ extension Contract { contract.resolve(result) }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -77,15 +77,15 @@ extension Contract { contract.resolve(result) }, onRejected: { _ in }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -118,15 +118,15 @@ extension Contract { contract.resolve($0) }, onRejected: { _ in }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract diff --git a/Source/Concurrency/Contract/Chain/ContractFinally.swift b/Source/Concurrency/Contract/Chain/ContractFinally.swift index 5339d6b..62cc57f 100644 --- a/Source/Concurrency/Contract/Chain/ContractFinally.swift +++ b/Source/Concurrency/Contract/Chain/ContractFinally.swift @@ -27,7 +27,7 @@ extension Contract { block() contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract diff --git a/Source/Concurrency/Contract/Chain/ContractRecover.swift b/Source/Concurrency/Contract/Chain/ContractRecover.swift index 751e2a1..fd3fa5e 100644 --- a/Source/Concurrency/Contract/Chain/ContractRecover.swift +++ b/Source/Concurrency/Contract/Chain/ContractRecover.swift @@ -29,7 +29,7 @@ extension Contract { contract.reject(error) } }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -69,11 +69,11 @@ extension Contract { defer { finish() } contract.reject($0) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } catch let error { @@ -81,7 +81,7 @@ extension Contract { contract.reject(error) } }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -105,7 +105,7 @@ extension Contract { let result = block(error) contract.resolve(result) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -144,14 +144,14 @@ extension Contract { defer { finish() } contract.reject($0) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract diff --git a/Source/Concurrency/Contract/Chain/ContractThen.swift b/Source/Concurrency/Contract/Chain/ContractThen.swift index 49956dc..f30f6bc 100644 --- a/Source/Concurrency/Contract/Chain/ContractThen.swift +++ b/Source/Concurrency/Contract/Chain/ContractThen.swift @@ -29,7 +29,7 @@ extension Contract { } }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -68,11 +68,11 @@ extension Contract { defer { finish() } contract.reject($0) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } catch let error { @@ -81,7 +81,7 @@ extension Contract { } }, onRejected: { error in contract.reject(error) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -105,7 +105,7 @@ extension Contract where Failure == Never { contract.resolve(result) }, onRejected: { _ in }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract @@ -143,15 +143,15 @@ extension Contract where Failure == Never { defer { finish() } contract.reject($0) }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, onRejected: { _ in }, - onCanceled: { contract.cancel() } + onCanceled: { [weak contract] in contract?.cancel() } ) return contract diff --git a/Source/Concurrency/Promise/Attribute/PromiseConvert.swift b/Source/Concurrency/Promise/Attribute/PromiseConvert.swift index df080ff..4a54d3d 100644 --- a/Source/Concurrency/Promise/Attribute/PromiseConvert.swift +++ b/Source/Concurrency/Promise/Attribute/PromiseConvert.swift @@ -31,7 +31,7 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -44,7 +44,7 @@ extension Promise { queue: queue, onResolved: { _ in promiseReturn.resolve(()) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -57,7 +57,7 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -72,7 +72,7 @@ extension Promise where Failure == Never { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -85,7 +85,7 @@ extension Promise where Failure == Never { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -98,7 +98,7 @@ extension Promise where Failure == Never { queue: queue, onResolved: { _ in promiseReturn.resolve(()) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -111,7 +111,7 @@ extension Promise where Failure == Never { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Attribute/PromiseDelay.swift b/Source/Concurrency/Promise/Attribute/PromiseDelay.swift index 8cf7735..f089433 100644 --- a/Source/Concurrency/Promise/Attribute/PromiseDelay.swift +++ b/Source/Concurrency/Promise/Attribute/PromiseDelay.swift @@ -37,7 +37,7 @@ extension Promise { } }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Attribute/PromiseTimeout.swift b/Source/Concurrency/Promise/Attribute/PromiseTimeout.swift index 1366832..2325fc1 100644 --- a/Source/Concurrency/Promise/Attribute/PromiseTimeout.swift +++ b/Source/Concurrency/Promise/Attribute/PromiseTimeout.swift @@ -39,7 +39,7 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) queue.asyncAfter(deadline: .now() + interval) { diff --git a/Source/Concurrency/Promise/Chain/PromiseCatch.swift b/Source/Concurrency/Promise/Chain/PromiseCatch.swift index 7e23c86..279491f 100644 --- a/Source/Concurrency/Promise/Chain/PromiseCatch.swift +++ b/Source/Concurrency/Promise/Chain/PromiseCatch.swift @@ -29,7 +29,7 @@ extension Promise { promiseReturn.reject(error) } }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -48,7 +48,7 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { block($0); promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Chain/PromiseFinally.swift b/Source/Concurrency/Promise/Chain/PromiseFinally.swift index 953ab5f..c42aa77 100644 --- a/Source/Concurrency/Promise/Chain/PromiseFinally.swift +++ b/Source/Concurrency/Promise/Chain/PromiseFinally.swift @@ -21,7 +21,7 @@ extension Promise { queue: queue, onResolved: { block(); promiseReturn.resolve($0) }, onRejected: { block(); promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Chain/PromiseRecover.swift b/Source/Concurrency/Promise/Chain/PromiseRecover.swift index b25d203..737920b 100644 --- a/Source/Concurrency/Promise/Chain/PromiseRecover.swift +++ b/Source/Concurrency/Promise/Chain/PromiseRecover.swift @@ -28,7 +28,7 @@ extension Promise { promiseReturn.reject(error) } }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -53,17 +53,17 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } catch let error { promiseReturn.reject(error) } }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -87,7 +87,7 @@ extension Promise { let value = block($0) promiseReturn.resolve(value) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -111,14 +111,14 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Chain/PromiseThen.swift b/Source/Concurrency/Promise/Chain/PromiseThen.swift index 4dadd95..ee34d36 100644 --- a/Source/Concurrency/Promise/Chain/PromiseThen.swift +++ b/Source/Concurrency/Promise/Chain/PromiseThen.swift @@ -28,7 +28,7 @@ extension Promise { } }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -52,18 +52,18 @@ extension Promise { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } catch let error { promiseReturn.reject(error) } }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -87,7 +87,7 @@ extension Promise where Failure == Never { promiseReturn.resolve(value) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn @@ -110,15 +110,15 @@ extension Promise where Failure == Never { queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) self?.subscribe( queue: queue, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) return promiseReturn diff --git a/Source/Concurrency/Promise/Composition/PromiseAll.swift b/Source/Concurrency/Promise/Composition/PromiseAll.swift index 519e325..8e34346 100644 --- a/Source/Concurrency/Promise/Composition/PromiseAll.swift +++ b/Source/Concurrency/Promise/Composition/PromiseAll.swift @@ -16,34 +16,29 @@ extension Promise where _ promises: [Promise] ) -> Promise<[Value0], Failure0> { let promiseReturn = Promise<[Value0], Failure0>(queue: queue) - let group = DispatchGroup() - - promises.forEach { promise in - group.enter() - var leave = Once { group.leave() } - promise.subscribe( - queue: promise.queue, - onResolved: { _ in leave() }, - onRejected: { promiseReturn.reject($0); leave() }, - onCanceled: { promiseReturn.cancel(); leave() } - ) - } - - group.notify(queue: queue) { + let resolve = { var values = [Value0]() - promises.forEach { promise in + for promise in promises { if case .resolved(let value) = promise.state.capture({ $0 }) { values.append(value) } - } - - if values.count != promises.count { - return + else { + return + } } promiseReturn.resolve(values) } + promises.forEach { promise in + promise.subscribe( + queue: promise.queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + } + return promiseReturn } @@ -53,26 +48,7 @@ extension Promise where _ promise1: Promise ) -> Promise<(Value0, Value1), Error> { let promiseReturn = Promise<(Value0, Value1), Error>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } - promise0.subscribe( - queue: queue, - onResolved: { _ in leave0() }, - onRejected: { promiseReturn.reject($0); leave0() }, - onCanceled: { promiseReturn.cancel(); leave0() } - ) - group.enter() - var leave1 = Once { group.leave() } - promise1.subscribe( - queue: queue, - onResolved: { _ in leave1() }, - onRejected: { promiseReturn.reject($0); leave1() }, - onCanceled: { promiseReturn.cancel(); leave1() } - ) - - group.notify(queue: queue) { + let resolve = { guard case .resolved(let value0) = promise0.state.capture({ $0 }), case .resolved(let value1) = promise1.state.capture({ $0 }) @@ -83,6 +59,19 @@ extension Promise where promiseReturn.resolve((value0, value1)) } + promise0.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + promise1.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + return promiseReturn } @@ -93,34 +82,7 @@ extension Promise where _ promise2: Promise ) -> Promise<(Value0, Value1, Value2), Error> { let promiseReturn = Promise<(Value0, Value1, Value2), Error>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } - promise0.subscribe( - queue: queue, - onResolved: { _ in leave0() }, - onRejected: { promiseReturn.reject($0); leave0() }, - onCanceled: { promiseReturn.cancel(); leave0() } - ) - group.enter() - var leave1 = Once { group.leave() } - promise1.subscribe( - queue: queue, - onResolved: { _ in leave1() }, - onRejected: { promiseReturn.reject($0); leave1() }, - onCanceled: { promiseReturn.cancel(); leave1() } - ) - group.enter() - var leave2 = Once { group.leave() } - promise2.subscribe( - queue: queue, - onResolved: { _ in leave2() }, - onRejected: { promiseReturn.reject($0); leave2() }, - onCanceled: { promiseReturn.cancel(); leave2() } - ) - - group.notify(queue: queue) { + let resolve = { guard case .resolved(let value0) = promise0.state.capture({ $0 }), case .resolved(let value1) = promise1.state.capture({ $0 }), @@ -132,6 +94,25 @@ extension Promise where promiseReturn.resolve((value0, value1, value2)) } + promise0.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + promise1.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + promise2.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + return promiseReturn } @@ -143,54 +124,44 @@ extension Promise where _ promise3: Promise ) -> Promise<(Value0, Value1, Value2, Value3), Error> { let promiseReturn = Promise<(Value0, Value1, Value2, Value3), Error>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } + let resolve = { + guard + case .resolved(let value0) = promise0.state.capture({ $0 }), + case .resolved(let value1) = promise1.state.capture({ $0 }), + case .resolved(let value2) = promise2.state.capture({ $0 }), + case .resolved(let value3) = promise3.state.capture({ $0 }) + else { + return + } + + promiseReturn.resolve((value0, value1, value2, value3)) + } + promise0.subscribe( queue: queue, - onResolved: { _ in leave0() }, - onRejected: { promiseReturn.reject($0); leave0() }, - onCanceled: { promiseReturn.cancel(); leave0() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave1 = Once { group.leave() } promise1.subscribe( queue: queue, - onResolved: { _ in leave1() }, - onRejected: { promiseReturn.reject($0); leave1() }, - onCanceled: { promiseReturn.cancel(); leave1() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave2 = Once { group.leave() } promise2.subscribe( queue: queue, - onResolved: { _ in leave2() }, - onRejected: { promiseReturn.reject($0); leave2() }, - onCanceled: { promiseReturn.cancel(); leave2() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave3 = Once { group.leave() } promise3.subscribe( queue: queue, - onResolved: { _ in leave3() }, - onRejected: { promiseReturn.reject($0); leave3() }, - onCanceled: { promiseReturn.cancel(); leave3() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.notify(queue: queue) { - guard - case .resolved(let value0) = promise0.state.capture({ $0 }), - case .resolved(let value1) = promise1.state.capture({ $0 }), - case .resolved(let value2) = promise2.state.capture({ $0 }), - case .resolved(let value3) = promise3.state.capture({ $0 }) - else { - return - } - - promiseReturn.resolve((value0, value1, value2, value3)) - } - return promiseReturn } @@ -203,63 +174,51 @@ extension Promise where _ promise4: Promise ) -> Promise<(Value0, Value1, Value2, Value3, Value4), Error> { let promiseReturn = Promise<(Value0, Value1, Value2, Value3, Value4), Error>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } + let resolve = { + guard + case .resolved(let value0) = promise0.state.capture({ $0 }), + case .resolved(let value1) = promise1.state.capture({ $0 }), + case .resolved(let value2) = promise2.state.capture({ $0 }), + case .resolved(let value3) = promise3.state.capture({ $0 }), + case .resolved(let value4) = promise4.state.capture({ $0 }) + else { + return + } + + promiseReturn.resolve((value0, value1, value2, value3, value4)) + } + promise0.subscribe( queue: queue, - onResolved: { _ in leave0() }, - onRejected: { promiseReturn.reject($0); leave0() }, - onCanceled: { promiseReturn.cancel(); leave0() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave1 = Once { group.leave() } promise1.subscribe( queue: queue, - onResolved: { _ in leave1() }, - onRejected: { promiseReturn.reject($0); leave1() }, - onCanceled: { promiseReturn.cancel(); leave1() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave2 = Once { group.leave() } promise2.subscribe( queue: queue, - onResolved: { _ in leave2() }, - onRejected: { promiseReturn.reject($0); leave2() }, - onCanceled: { promiseReturn.cancel(); leave2() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave3 = Once { group.leave() } promise3.subscribe( queue: queue, - onResolved: { _ in leave3() }, - onRejected: { promiseReturn.reject($0); leave3() }, - onCanceled: { promiseReturn.cancel(); leave3() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave4 = Once { group.leave() } promise4.subscribe( queue: queue, - onResolved: { _ in leave4() }, - onRejected: { promiseReturn.reject($0); leave4() }, - onCanceled: { promiseReturn.cancel(); leave4() } + onResolved: { _ in resolve() }, + onRejected: { promiseReturn.reject($0) }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.notify(queue: queue) { - guard - case .resolved(let value0) = promise0.state.capture({ $0 }), - case .resolved(let value1) = promise1.state.capture({ $0 }), - case .resolved(let value2) = promise2.state.capture({ $0 }), - case .resolved(let value3) = promise3.state.capture({ $0 }), - case .resolved(let value4) = promise4.state.capture({ $0 }) - else { - return - } - - promiseReturn.resolve((value0, value1, value2, value3, value4)) - } - return promiseReturn } } @@ -274,26 +233,7 @@ extension Promise where _ promise1: Promise ) -> Promise<(Value0, Value1), Never> { let promiseReturn = Promise<(Value0, Value1), Never>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } - promise0.subscribe( - queue: queue, - onResolved: { _ in leave0() }, - onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave0() } - ) - group.enter() - var leave1 = Once { group.leave() } - promise1.subscribe( - queue: queue, - onResolved: { _ in leave1() }, - onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave1() } - ) - - group.notify(queue: queue) { + let resolve = { guard case .resolved(let value0) = promise0.state.capture({ $0 }), case .resolved(let value1) = promise1.state.capture({ $0 }) @@ -304,6 +244,19 @@ extension Promise where promiseReturn.resolve((value0, value1)) } + promise0.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { _ in }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + promise1.subscribe( + queue: queue, + onResolved: { _ in resolve() }, + onRejected: { _ in }, + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } + ) + return promiseReturn } @@ -314,45 +267,37 @@ extension Promise where _ promise2: Promise ) -> Promise<(Value0, Value1, Value2), Never> { let promiseReturn = Promise<(Value0, Value1, Value2), Never>(queue: queue) - let group = DispatchGroup() + let resolve = { + guard + case .resolved(let value0) = promise0.state.capture({ $0 }), + case .resolved(let value1) = promise1.state.capture({ $0 }), + case .resolved(let value2) = promise2.state.capture({ $0 }) + else { + return + } + + promiseReturn.resolve((value0, value1, value2)) + } - group.enter() - var leave0 = Once { group.leave() } promise0.subscribe( queue: queue, - onResolved: { _ in leave0() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave0() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave1 = Once { group.leave() } promise1.subscribe( queue: queue, - onResolved: { _ in leave1() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave1() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave2 = Once { group.leave() } promise2.subscribe( queue: queue, - onResolved: { _ in leave2() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave2() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.notify(queue: queue) { - guard - case .resolved(let value0) = promise0.state.capture({ $0 }), - case .resolved(let value1) = promise1.state.capture({ $0 }), - case .resolved(let value2) = promise2.state.capture({ $0 }) - else { - return - } - - promiseReturn.resolve((value0, value1, value2)) - } - return promiseReturn } @@ -364,54 +309,44 @@ extension Promise where _ promise3: Promise ) -> Promise<(Value0, Value1, Value2, Value3), Never> { let promiseReturn = Promise<(Value0, Value1, Value2, Value3), Never>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } + let resolve = { + guard + case .resolved(let value0) = promise0.state.capture({ $0 }), + case .resolved(let value1) = promise1.state.capture({ $0 }), + case .resolved(let value2) = promise2.state.capture({ $0 }), + case .resolved(let value3) = promise3.state.capture({ $0 }) + else { + return + } + + promiseReturn.resolve((value0, value1, value2, value3)) + } + promise0.subscribe( queue: queue, - onResolved: { _ in leave0() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave0() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave1 = Once { group.leave() } promise1.subscribe( queue: queue, - onResolved: { _ in leave1() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave1() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave2 = Once { group.leave() } promise2.subscribe( queue: queue, - onResolved: { _ in leave2() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave2() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave3 = Once { group.leave() } promise3.subscribe( queue: queue, - onResolved: { _ in leave3() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave3() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.notify(queue: queue) { - guard - case .resolved(let value0) = promise0.state.capture({ $0 }), - case .resolved(let value1) = promise1.state.capture({ $0 }), - case .resolved(let value2) = promise2.state.capture({ $0 }), - case .resolved(let value3) = promise3.state.capture({ $0 }) - else { - return - } - - promiseReturn.resolve((value0, value1, value2, value3)) - } - return promiseReturn } @@ -424,76 +359,51 @@ extension Promise where _ promise4: Promise ) -> Promise<(Value0, Value1, Value2, Value3, Value4), Never> { let promiseReturn = Promise<(Value0, Value1, Value2, Value3, Value4), Never>(queue: queue) - let group = DispatchGroup() - - group.enter() - var leave0 = Once { group.leave() } + let resolve = { + guard + case .resolved(let value0) = promise0.state.capture({ $0 }), + case .resolved(let value1) = promise1.state.capture({ $0 }), + case .resolved(let value2) = promise2.state.capture({ $0 }), + case .resolved(let value3) = promise3.state.capture({ $0 }), + case .resolved(let value4) = promise4.state.capture({ $0 }) + else { + return + } + + promiseReturn.resolve((value0, value1, value2, value3, value4)) + } + promise0.subscribe( queue: queue, - onResolved: { _ in leave0() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave0() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave1 = Once { group.leave() } promise1.subscribe( queue: queue, - onResolved: { _ in leave1() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave1() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave2 = Once { group.leave() } promise2.subscribe( queue: queue, - onResolved: { _ in leave2() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave2() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave3 = Once { group.leave() } promise3.subscribe( queue: queue, - onResolved: { _ in leave3() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave3() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.enter() - var leave4 = Once { group.leave() } promise4.subscribe( queue: queue, - onResolved: { _ in leave4() }, + onResolved: { _ in resolve() }, onRejected: { _ in }, - onCanceled: { promiseReturn.cancel(); leave4() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) - group.notify(queue: queue) { - guard - case .resolved(let value0) = promise0.state.capture({ $0 }), - case .resolved(let value1) = promise1.state.capture({ $0 }), - case .resolved(let value2) = promise2.state.capture({ $0 }), - case .resolved(let value3) = promise3.state.capture({ $0 }), - case .resolved(let value4) = promise4.state.capture({ $0 }) - else { - return - } - - promiseReturn.resolve((value0, value1, value2, value3, value4)) - } - return promiseReturn } } - -private struct Once { - var isCalled = false - let block: () -> Void - - mutating func callAsFunction() { - if !isCalled { - block() - } - - isCalled = true - } -} diff --git a/Source/Concurrency/Promise/Composition/PromiseRace.swift b/Source/Concurrency/Promise/Composition/PromiseRace.swift index f685169..5970276 100644 --- a/Source/Concurrency/Promise/Composition/PromiseRace.swift +++ b/Source/Concurrency/Promise/Composition/PromiseRace.swift @@ -22,7 +22,7 @@ extension Promise where queue: queue, onResolved: { promiseReturn.resolve($0) }, onRejected: { promiseReturn.reject($0) }, - onCanceled: { promiseReturn.cancel() } + onCanceled: { [weak promiseReturn] in promiseReturn?.cancel() } ) } diff --git a/Source/Concurrency/Promise/Promise.swift b/Source/Concurrency/Promise/Promise.swift index 5761e6e..269dc78 100644 --- a/Source/Concurrency/Promise/Promise.swift +++ b/Source/Concurrency/Promise/Promise.swift @@ -72,7 +72,7 @@ extension Promise where Failure == Error { try block( { self.resolve($0) }, { self.reject($0) }, - { self.cancel() }, + { [weak self] in self?.cancel() }, { self.subscribe(queue: queue, onCanceled: $0) } ) } catch let error { @@ -112,7 +112,7 @@ extension Promise where Failure == Never { block( { self.resolve($0) }, { _ in }, - { self.cancel() }, + { [weak self] in self?.cancel() }, { self.subscribe(queue: queue, onCanceled: $0) } ) } @@ -155,7 +155,7 @@ extension Promise where queue: queue, onResolved: { promise.resolve($0) }, onRejected: { promise.reject($0) }, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } catch let error { promise.reject(error) @@ -191,7 +191,7 @@ extension Promise where queue: queue, onResolved: { promise.resolve($0) }, onRejected: { promise.reject($0) }, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } @@ -210,7 +210,7 @@ extension Promise where queue: queue, onResolved: { promise.resolve($0) }, onRejected: { _ in }, - onCanceled: { promise.cancel() } + onCanceled: { [weak promise] in promise?.cancel() } ) } diff --git a/Test/Concurrency/Promise/Attribute/PromiseDelayTest.swift b/Test/Concurrency/Promise/Attribute/PromiseDelayTest.swift index 88c2aaa..60787dc 100644 --- a/Test/Concurrency/Promise/Attribute/PromiseDelayTest.swift +++ b/Test/Concurrency/Promise/Attribute/PromiseDelayTest.swift @@ -61,18 +61,18 @@ final class PromiseDelayTest: XCTestCase { let end = DispatchSemaphore(value: 0) var promiseCancel: (() -> Void)? - let promise = Promise { resolve, reject, cancel, _ in + let promise0 = Promise { resolve, reject, cancel, _ in promiseCancel = cancel resolve(20) } - .delay(.milliseconds(100)) - .then { _ in + let promise1 = promise0.delay(.milliseconds(100)) + let promise2 = promise1.then { _ in promiseCancel?() end.signal() } PromiseTest.expect(semaphore: end, timeout: .seconds(1)) - PromiseTest.expect(promise: promise, state: .canceled, timeout: .seconds(1)) + PromiseTest.expect(promise: promise2, state: .canceled, timeout: .seconds(1)) } func test__never_delay_create() { diff --git a/Test/Concurrency/Promise/Chain/PromiseCatchTest.swift b/Test/Concurrency/Promise/Chain/PromiseCatchTest.swift index 1c01e38..b95d5ab 100644 --- a/Test/Concurrency/Promise/Chain/PromiseCatchTest.swift +++ b/Test/Concurrency/Promise/Chain/PromiseCatchTest.swift @@ -42,16 +42,16 @@ final class PromiseCatchTest: XCTestCase { let end = DispatchSemaphore(value: 0) var promiseCancel: (() -> Void)? - let promise = Promise { resolve, reject, cancel, _ in + let promise0 = Promise { resolve, reject, cancel, _ in promiseCancel = cancel throw PromiseTest.SampleError.one } - .catch { error in + let promise1 = promise0.catch { error in promiseCancel?() end.signal() } PromiseTest.expect(semaphore: end, timeout: .seconds(1)) - PromiseTest.expect(promise: promise, state: .canceled, timeout: .seconds(1)) + PromiseTest.expect(promise: promise1, state: .canceled, timeout: .seconds(1)) } } diff --git a/Test/Concurrency/Promise/Chain/PromiseFinallyTest.swift b/Test/Concurrency/Promise/Chain/PromiseFinallyTest.swift index 34e26e4..a5e9c99 100644 --- a/Test/Concurrency/Promise/Chain/PromiseFinallyTest.swift +++ b/Test/Concurrency/Promise/Chain/PromiseFinallyTest.swift @@ -41,16 +41,16 @@ final class PromiseFinallyTest: XCTestCase { let end = DispatchSemaphore(value: 0) var promiseCancel: (() -> Void)? - let promise = Promise { resolve, reject, cancel, _ in + let promise0 = Promise { resolve, reject, cancel, _ in promiseCancel = cancel throw PromiseTest.SampleError.one } - .finally { + let promise1 = promise0.finally { promiseCancel?() end.signal() } PromiseTest.expect(semaphore: end, timeout: .seconds(1)) - PromiseTest.expect(promise: promise, state: .canceled, timeout: .seconds(1)) + PromiseTest.expect(promise: promise1, state: .canceled, timeout: .seconds(1)) } } diff --git a/Test/Concurrency/Promise/Chain/PromiseRecoverTest.swift b/Test/Concurrency/Promise/Chain/PromiseRecoverTest.swift index defe472..efa9974 100644 --- a/Test/Concurrency/Promise/Chain/PromiseRecoverTest.swift +++ b/Test/Concurrency/Promise/Chain/PromiseRecoverTest.swift @@ -129,18 +129,18 @@ final class PromiseRecoverTest: XCTestCase { var promiseCancel: (() -> Void)? let recoverPromise = Promise.pending().promise - let promise = Promise { resolve, reject, cancel, _ in + let promise0 = Promise { resolve, reject, cancel, _ in promiseCancel = cancel throw PromiseTest.SampleError.one } - .recover { error in + let promise1 = promise0.recover { error in promiseCancel?() end.signal() return recoverPromise } PromiseTest.expect(semaphore: end, timeout: .seconds(1)) - PromiseTest.expect(promise: promise, state: .canceled, timeout: .seconds(1)) + PromiseTest.expect(promise: promise1, state: .canceled, timeout: .seconds(1)) PromiseTest.expect(promise: recoverPromise, state: .canceled, timeout: .seconds(1)) } } diff --git a/Test/Concurrency/Promise/Chain/PromiseThenTest.swift b/Test/Concurrency/Promise/Chain/PromiseThenTest.swift index 239f18b..ef98bfc 100644 --- a/Test/Concurrency/Promise/Chain/PromiseThenTest.swift +++ b/Test/Concurrency/Promise/Chain/PromiseThenTest.swift @@ -159,18 +159,18 @@ final class PromiseThenTest: XCTestCase { var promiseCancel: (() -> Void)? let thenPromise = Promise.pending().promise - let promise = Promise { resolve, reject, cancel, _ in + let promise0 = Promise { resolve, reject, cancel, _ in promiseCancel = cancel resolve(10) } - .then { _ in + let promise1 = promise0.then { _ in promiseCancel?() end.signal() return thenPromise } PromiseTest.expect(semaphore: end, timeout: .seconds(1)) - PromiseTest.expect(promise: promise, state: .canceled, timeout: .seconds(1)) + PromiseTest.expect(promise: promise1, state: .canceled, timeout: .seconds(1)) PromiseTest.expect(promise: thenPromise, state: .canceled, timeout: .seconds(1)) }