Skip to content

Conversation

@viachaslauinnowise
Copy link

Fix: memory leaks in AppStateListener observers and Room cleanup

AppStateListener:

  • Store NotificationCenter observer tokens for proper cleanup
  • Add deinit to remove all observers
  • Use [weak self] in all observer closures

Room:

  • Remove from AppStateListener.delegates in deinit (safety net)
  • Explicitly remove in cleanUp() (primary path)
  • Prevent memory leaks when Room is destroyed without cleanUp()

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.


// Stop listening to app state changes to avoid retaining Room longer than needed
await MainActor.run {
AppStateListener.shared.delegates.remove(delegate: self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is needed if AppStateListener uses:

private struct State {
  let delegates = NSHashTable<AnyObject>.weakObjects()
}

}

deinit {
for (center, token) in _observerTokens {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a singleton, so where the removal will occur?

Copy link
Contributor

@pblazej pblazej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you see in the other PR(s) there's ongoing work to improve Swift concurrency and memory management in general, so thank you for bringing this topic.

However, this PR:

  • does not provide any evidence that such leaks occur
  • breaks reconnection semantics (as AppStateListener is added on init but removed during cleanup() now)
  • abuses deinit introducing unsafe unowned

If we want to introduce some best practices here, we can try modernizing AppStateListener by leveraging Combine observers (AsyncStream is supported in iOS 15).

Otherwise, I'd suggest closing this PR.

@pblazej pblazej closed this Jan 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants