Cleanup when an effect is cancelled #2051
lukeredpath
started this conversation in
General
Replies: 1 comment
-
I know this is a year old, but was looking for an answer to the same question and found this which seems to work in my use case which is to use |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I've been exploring different ways of performing some kind of cleanup when an effect is cancelled and I've found there is a scenario where it doesn't seem to be possible.
To take a trivial example, lets say you set some boolean flag to indicate when a network request is in flight - you want to set this back to false when the effect completes:
The question is - how to deal with cancellation? If the effect is cancelled for some reason, we still want to ensure the
networkRequestInFlight
is set back tofalse
again.As far as I can tell, there are three main forms of cancellation. The first is when the effect, or some dependency, indicates cancellation by throwing a cancellation error. We can handle this just fine - for the purposes of this example
TaskResult.catching
is a custom extension that causesTaskResult
not to catch cancellation errors:Another case is when we use TCA's cancellation tools to explicitly cancel the effect - in this case, we would trigger this from some other action so we already have a natural place to deal with this cleanup:
Technically we're setting the flag to false optimistically because returning the
cancel
effect doesn't guarantee that the effect cancels immediately but for all intents and purposes this is good enough.The final case is one that I cannot currently see a way of handling and that is where the effect is cancelled by calling
.cancel()
on theViewStoreTask
(orTestStoreTask
in tests), typically when an effect is tied to a view's lifecycle using SwiftUI's.task
modifier. A lot of the time this is fine if the effect is being cancelled when the view is going away completely as there's typically no longer any state to clean up - however there is a use case for effect cancellation tied to a view's lifecycle when a view can appear and disappear many times without its state going away, e.g. a row in aList
that triggers some effect on appear but cancels it again on disappear. In this scenario there is no way of catching the cancellation:In my testing, there is no way of catching this "external" cancellation other than by using
withTaskCancellationHandler(_:onCancel:)
in your effect'srun
closure, however there are two problems with this:send
inside theonCancel
closure as it is a synchronous isolated context and,Send
specifically guards againstTask.isCancelled
and acts as a no-op if the current task is cancelled.What tools could TCA potentially provide to make this third scenario possible? I've put together some test cases that demo these three different scenarios here: main...lukeredpath:swift-composable-architecture:handle-cancellation
Beta Was this translation helpful? Give feedback.
All reactions