cocos2dx EventListenerCustom 和NotificationCenter的优缺点

来源:互联网 发布:出国留学值得吗 知乎 编辑:程序博客网 时间:2024/05/24 04:17

(本人总结,如有不对,请多多指正)

自从cocos2dx 3.x后,NotificationCenter就标记为废弃了,而是用EventListenerCustom代替

NotificationCenter 实现很简单,里面有着数组NotificationObserver

当你注册了一个消息的同时,也注册了消息所响应的函数,这些包含在NotificationObserver类中,当有消息发出时,NotificationCenter就循环NotificationObserver

,如果名称对应,结点对应,就直接调用函数,代码如下

CCARRAY_FOREACH(ObserversCopy, obj)    {        NotificationObserver* observer = static_cast<NotificationObserver*>(obj);        if (!observer)            continue;                if (observer->getName() == name && (observer->getSender() == sender || observer->getSender() == nullptr || sender == nullptr))        {            if (0 == observer->getHandler())            {                observer->performSelector(sender);            }        }    }

而EventListenerCustom就不同,和EventListenerTouchOneByOne等相同,它们内部是通过EventDispatcher发送和响应消息的。EventDispatcher是单例类,保存在Director中,其他Node保存的只是它的引用。通过EventListenerCuston发送消息有一个弊端,就是消息有可能不能被接收,即当你发送消息而对应的函数可能没有被调用。

看Node中的onEnter代码

void Node::onEnter(){#if CC_ENABLE_SCRIPT_BINDING    if (_scriptType == kScriptTypeJavascript)    {        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnEnter))            return;    }#endif        if (_onEnterCallback)        _onEnterCallback();    if (_componentContainer && !_componentContainer->isEmpty())    {        _componentContainer->onEnter();    }        _isTransitionFinished = false;        for( const auto &child: _children)        child->onEnter();        this->resume();//重点是这句        _running = true;    #if CC_ENABLE_SCRIPT_BINDING    if (_scriptType == kScriptTypeLua)    {        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnEnter);    }#endif}

接下来看看this->resume()做了什么

void Node::resume(){    _scheduler->resumeTarget(this);    _actionManager->resumeTarget(this);    _eventDispatcher->resumeEventListenersForTarget(this);//重点}
一般情况下 Node::onEnter()是在addChild中是被调用的,而场景类的onEnter()是在切换场景是被调用的,如下

void Director::setNextScene(){    bool runningIsTransition = dynamic_cast<TransitionScene*>(_runningScene) != nullptr;    bool newIsTransition = dynamic_cast<TransitionScene*>(_nextScene) != nullptr;    // If it is not a transition, call onExit/cleanup     if (! newIsTransition)     {         if (_runningScene)         {             _runningScene->onExitTransitionDidStart();             _runningScene->onExit();         }          // issue #709. the root node (scene) should receive the cleanup message too         // otherwise it might be leaked.         if (_sendCleanupToScene && _runningScene)         {             _runningScene->cleanup();         }     }    if (_runningScene)    {        _runningScene->release();    }    _runningScene = _nextScene;    _nextScene->retain();    _nextScene = nullptr;    if ((! runningIsTransition) && _runningScene)    {        _runningScene->onEnter();//重点        _runningScene->onEnterTransitionDidFinish();    }}

也就是说,你在层或者场景的init里是无法通过EventListenerCustom发送事件的。因为当时的事件是暂停的

if (sceneGraphPriorityListeners)    {        if (!shouldStopPropagation)        {            // priority == 0, scene graph priority            for (auto& l : *sceneGraphPriorityListeners)            {                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))//重点                {                    shouldStopPropagation = true;                    break;                }            }        }    }

所以个人认为,NotificationCenter和EventListenerCustom并没有孰优孰劣,看个人需求
下面总结相同点和不同点

相同点:都能发送消息从而使对应的函数被调用

不同点 NotificaCenter需要显式地移除,EventListenerCustom只有在场景跑起来后才可以响应


1 0