在Unity中,OnEnable方法会在对象激活时被调用,而SetActive(true)会触发这个过程。如果在OnEnable里注册事件,且多次激活对象,就会造成事件重复注册,进而使同一个事件被多次触发。下面为你提供几种解决办法。


方案一:注册前先取消注册

在注册事件之前,先确保该事件没有被注册,这能避免重复注册。

private void OnEnable()
{
    // 先取消注册,再注册
    SomeEvent -= HandleEvent;
    SomeEvent += HandleEvent;
}

private void OnDisable()
{
    // 取消注册事件
    SomeEvent -= HandleEvent;
}

方案二:使用标志位避免重复注册

借助一个标志位来判断事件是否已经注册,防止重复操作。

private bool _isEventRegistered = false;

private void OnEnable()
{
    if (!_isEventRegistered)
    {
        SomeEvent += HandleEvent;
        _isEventRegistered = true;
    }
}

private void OnDisable()
{
    if (_isEventRegistered)
    {
        SomeEvent -= HandleEvent;
        _isEventRegistered = false;
    }
}

方案三:在Awake中注册事件

Awake方法里注册事件,因为Awake只会在对象的生命周期中调用一次,这样可以避免重复注册。

private void Awake()
{
    // 在Awake中注册,仅调用一次
    SomeEvent += HandleEvent;
}

private void OnDisable()
{
    // 取消注册事件
    SomeEvent -= HandleEvent;
}

方案四:使用单例模式

要是你的组件采用单例模式,那么可以在初始化时注册事件。

private static MyClass _instance;
public static MyClass Instance
{
    get
    {
        if (_instance == null)
        {
            _instance = FindObjectOfType<MyClass>();
            if (_instance == null)
            {
                GameObject obj = new GameObject();
                obj.name = typeof(MyClass).Name;
                _instance = obj.AddComponent<MyClass>();
            }
            // 初始化时注册事件
            _instance.Initialize();
        }
        return _instance;
    }
}

private void Initialize()
{
    SomeEvent += HandleEvent;
}

private void OnDisable()
{
    if (_instance == this)
    {
        SomeEvent -= HandleEvent;
    }
}

方案五:利用WeakEvent模式(适合特殊场景)

对于需要避免内存泄漏的情况,可以考虑使用WeakEvent模式。不过这种模式实现起来较为复杂。

// 需要实现WeakEventManager类
private void OnEnable()
{
    WeakEventManager.AddHandler(SomeEvent, HandleEvent);
}

private void OnDisable()
{
    WeakEventManager.RemoveHandler(SomeEvent, HandleEvent);
}

最佳实践建议

  • 优先选用方案一,这种方法简单直接,能够有效避免重复注册。
  • 如果事件注册依赖于对象状态,方案二是不错的选择。
  • 若组件在场景中会频繁激活和禁用,推荐使用方案三。
  • 方案四适用于单例组件。
  • 方案五适合对内存管理有严格要求的场景。

通过上述方法,你可以解决OnEnable中事件重复注册的问题,保证事件处理的准确性。