How TEngine Automatically Cleans Up Events When UI Is Destroyed

TEngine automatically removes UI event listeners by storing them in a GameEventMgr instance that clears all registered delegates when the UIBase class receives Unity's OnDestroy callback.

The alex-rachel/tengine framework eliminates manual event unsubscription in Unity UI development through an automated lifecycle management system. By coupling each UI component with a dedicated GameEventMgr instance, TEngine ensures that automatically clean up events when UI is destroyed happens without developer intervention, preventing memory leaks and null reference exceptions.

The Architecture Behind Automatic Event Cleanup

GameEventMgr: The Central Registry

Located at UnityProject/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs, the GameEventMgr class implements IMemory and maintains two parallel collections to track registrations:

  • _listEventTypes: A List<int> storing integer event identifiers
  • _listHandles: A List<Delegate> storing the corresponding handler references

When AddEvent() is called, the method registers the listener with the global GameEvent dispatcher and records the pairing internally via AddEventImp(). This dual-tracking enables bulk cleanup later.

UIBase: The Lifecycle Bridge

The UIBase class at UnityProject/Assets/TEngine/Runtime/Module/UILifecycle/UIBase.cs provides the critical link between Unity's destruction phase and TEngine's cleanup logic. Every UI component inherits a protected _eventMgr field initialized to new GameEventMgr().

The base class overrides OnDestroy() to invoke _eventMgr.Clear(), ensuring that automatically clean up events when UI is destroyed occurs precisely when the GameObject is destroyed.

Step-by-Step Cleanup Process

  1. Event Registration: When a UI script calls AddUIEvent(eventType, handler), the base class forwards this to _eventMgr.AddEvent(). This registers with GameEvent.AddEventListener() and stores the mapping in _listEventTypes and _listHandles.

  2. Destruction Trigger: Unity calls MonoBehaviour.OnDestroy() when the UI GameObject is destroyed.

  3. Cleanup Invocation: The UIBase.OnDestroy() override executes _eventMgr.Clear().

  4. Listener Removal: The Clear() method iterates through all stored pairs and unregisters them:

    for (int i = 0; i < _listEventTypes.Count; ++i)
    {
        var eventType = _listEventTypes[i];
        var handle    = _listHandles[i];
        GameEvent.RemoveEventListener(eventType, handle);
    }
  5. Reference Release: After unregistering from the global dispatcher, _listEventTypes.Clear() and _listHandles.Clear() remove all references, allowing the garbage collector to reclaim the UI object's memory.

Practical Implementation Example

using UnityEngine;
using System;

public class InventoryPanel : UIBase
{
    private const int UpdateInventoryEvent = 2001;

    private void Start()
    {
        // Register event - no manual cleanup needed
        AddUIEvent(UpdateInventoryEvent, RefreshInventory);
    }

    private void RefreshInventory()
    {
        Debug.Log("Refreshing inventory display");
    }

    // Cleanup happens automatically in UIBase.OnDestroy()
}

This pattern applies to any class inheriting from UIBase. The framework handles the entire lifecycle, allowing developers to focus on business logic rather than subscription management.

Memory Safety Benefits

The automatically clean up events when UI is destroyed mechanism prevents two common Unity pitfalls:

  • Memory leaks: Stale delegate references keep destroyed UI objects alive in the global GameEvent dispatcher
  • Null reference exceptions: Callbacks firing on destroyed MonoBehaviours after scene transitions

By encapsulating the cleanup in GameEventMgr.Clear() and triggering it through UIBase.OnDestroy(), TEngine guarantees that no dangling callbacks remain when UI objects are destroyed.

Summary

  • TEngine stores UI event registrations in the GameEventMgr class located at UnityProject/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs
  • The UIBase class at UnityProject/Assets/TEngine/Runtime/Module/UILifecycle/UIBase.cs provides automatic cleanup by calling _eventMgr.Clear() in its OnDestroy() override
  • Clear() iterates through _listEventTypes and _listHandles to call GameEvent.RemoveEventListener() for every registered delegate
  • Developers using UIBase never need to manually unregister events; the framework handles cleanup when Unity destroys the GameObject
  • This design prevents memory leaks and null reference exceptions by ensuring zero orphaned callbacks after UI destruction

Frequently Asked Questions

What triggers the automatic cleanup in TEngine?

Unity's OnDestroy lifecycle method triggers the cleanup. When a UI GameObject is destroyed, the UIBase class receives the OnDestroy callback and immediately invokes _eventMgr.Clear(), which removes all registered listeners from the global GameEvent dispatcher.

Do I need to manually unregister events in TEngine UI classes?

No. When you inherit from UIBase and use AddUIEvent() or _eventMgr.AddEvent(), the framework automatically tracks all registrations. The Clear() method in GameEventMgr.cs handles unregistration when the UI is destroyed, eliminating the need for manual cleanup code in your UI scripts.

What happens if I don't use UIBase for my UI components?

Without inheriting from UIBase, you lose the automatic cleanup mechanism. You would need to manually manage a GameEventMgr instance and ensure you call Clear() during your component's destruction phase. The base class exists specifically to provide this lifecycle management automatically.

Where is the cleanup logic located in the source code?

The cleanup implementation spans two critical files: UnityProject/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs contains the Clear() method that iterates through _listEventTypes and _listHandles to call GameEvent.RemoveEventListener(), while UnityProject/Assets/TEngine/Runtime/Module/UILifecycle/UIBase.cs provides the OnDestroy() override that triggers this cleanup process.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →