I noticed that when using cancellable effects inside IfLetStore view, the publishers of the effects are retained in the memory after the effect is canceled.
We dug into this a bit more and think we figured it out. If you swap out your custom timer publisher for Effect.timer we don't seem to get a memory leak at all:
Effect.timer(id: "", every: 1, tolerance: 0, on: scheduler)
Long-living effects are retained by cancellation ID, so if a custom publisher does some cancellation logic under the hood you need to forward on any cancel tokens on accordingly. If you want to control a timer-based effect outside of cancellation, you can use Publishers.Timer, defined in the combine-schedulers package that swift-composable-architecture uses: combine-schedulers/Timer.swift at ff42ec9061d864de7982162011321d3df5080c10 · pointfreeco/combine-schedulers · GitHub
Thanks for the reply, Stephen! You are totally right, I made a mistake and used Effect.timer inside my custom timer implementation. However, I think it wasn't a source of the problem. I replaced Effect.timer with Swift.Timer so my publisher no longer depends on TCA. The issue with publishers being retained after cancellation is still there
@darrarski Is there a reason that you can't use Effect.timer directly, which doesn't exhibit this problem? If you can determine that you've found a bug that is definitely library-related we'd love to fix it, but right now the custom publisher adds enough complexity that it's difficult to troubleshoot if this is a bug with the Composable Architecture, Combine, the custom publisher, or something else. Do you think it's possible to reduce the issue to a failing unit test that can be PR'd?
We already have a couple of test suites going for memory management and cancellation:
The timer itself is not an issue here I experienced the memory retain problem while working on another project, where I create a long-time-running effect from CoreData fetch request publisher. I noticed the issue is reproducible with any custom publisher I made. I am still not sure if the problem is caused by the TCA or my custom publishers.
Thanks for the advise, I will try to create a PR with failing unit test in TCA repository
Good news. I was able to narrow the scope in my demo project and locate a single operator that, when used, is causing publishers to be retained. It looks like the problem might be in a place I didn't look at before.
It looks like the issue is not connected to IfLetStore or .optional operator on a Reducer. It's strange that just using the Reducer.combine makes it retain publishers when effects are cancelled.
I am pleased to inform that the issue no longer occurs when using Xcode 12.1 (12A7403) with Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)