• cocos2dx 解释二具体的启动过程:内存管理和回调


    在上一篇的第二部分中。我们有一句代码待解释的:
    // Draw the Scene
    void CCDirector::drawScene(void)
    {
    …...
        //tick before glClear: issue #533
    if (! m_bPaused) //暂停
    {
    m_pScheduler->update(m_fDeltaTime);   //待会会解释这里的内容
    }
    …...
    }
    这里是一个update函数,常常会写像this->schedule(schedule_selector(XXX::update))这种调用方式,我们看看schedule:
    在CCDirector中有:
        /** CCScheduler associated with this director
    @since v2.0
    */
    CC_PROPERTY(CCScheduler*, m_pScheduler, Scheduler);
    来跟踪看一下:
    /** CC_PROPERTY is used to declare a protected variable.
    We can use getter to read the variable, and use the setter to change the variable.
    @param varType : the type of variable.
    @param varName : variable name.
    @param funName : "get + funName" is the name of the getter.
    "set + funName" is the name of the setter.
    @warning : The getter and setter are public virtual functions, you should rewrite them first.
    The variables and methods declared after CC_PROPERTY are all public.
    If you need protected or private, please declare.
    */
    #define CC_PROPERTY(varType, varName, funName)
    protected: varType varName;
    public: virtual varType get##funName(void);
    public: virtual void set##funName(varType var);
    写过代码的 这个宏应该不会陌生吧。


    可是。在CCDirector中的CCScheduler 变量 m_pScheduler是什么 ?  能够透露一下 他跟 CCNode有一定的联系。

    为什么?  来看一下 CCScheduler的 update函数吧:
    // main loop
    void CCScheduler::update(float dt)
    {
         ……
         


    // The 'timers' array may change while inside this loop
    for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
    {
    elt->currentTimer = (CCTimer*)(elt->timers->arr[elt->timerIndex]);
    elt->currentTimerSalvaged = false;

    elt->currentTimer->update(dt);   //这里又有一个update函数哟

    if (elt->currentTimerSalvaged)
    {
    // The currentTimer told the remove itself. To prevent the timer from
    // accidentally deallocating itself before finishing its step, we retained
    // it. Now that step is done, it's safe to release it.
    elt->currentTimer->release();
    }

    elt->currentTimer = NULL;
    }

         …...
    }

    我们继续跟进 这个update函数。能够看到他是调用的CCTimer的update函数:
    yoxi~~  这里但是有非常多selector的哟~~
    void CCTimer::update(float dt)
    {
    …..
            if (m_bRunForever && !m_bUseDelay)
    {//standard timer usage
    m_fElapsed += dt;
    if (m_fElapsed >= m_fInterval)
    {
    if (m_pTarget && m_pfnSelector)
    {
    (m_pTarget->*m_pfnSelector)(m_fElapsed);   //第一个出现了
                    }

                  …..
    if( m_fElapsed >= m_fDelay )
    {
    if (m_pTarget && m_pfnSelector)
    {
    (m_pTarget->*m_pfnSelector)(m_fElapsed);  //第二个出现了
                        }

                       ……..
    else
    {
    if (m_fElapsed >= m_fInterval)
    {
    if (m_pTarget && m_pfnSelector)
    {
    (m_pTarget->*m_pfnSelector)(m_fElapsed);  //第三个出现了
    }

    ……..
    }

    这是什么?  (m_pTarget->*m_pfnSelector)(m_fElapsed);
    怎么有点诡异啊,看不懂?  没关系,来看看刚刚提到的update的调用。比較一下:
    this->schedule(schedule_selector(XXX::update)
    跟进吧。看schedule得实现来:
    void CCNode::schedule(SEL_SCHEDULE selector, float interval)
    {
    this->schedule(selector, interval, kCCRepeatForever, 0.0f);
    }

    void CCNode::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)
    {
    CCAssert( selector, "Argument must be non-nil");
    CCAssert( interval >=0, "Argument must be positive");

    m_pScheduler->scheduleSelector(selector, this, interval , repeat, delay, !m_bRunning);
    }

    哇哟,看最后一句咯~ 拿出来比較比較:
    (m_pTarget->*m_pfnSelector)(m_fElapsed);
    m_pScheduler->scheduleSelector(selector, this, interval , repeat, delay, !m_bRunning);
    这是什么情况啊 ?  selector是什么? 看參数SEL_SCHEDULE:
    typedef void (CCObject::*SEL_SCHEDULE)(float);
    NO, 这是什么?  这不是函数指针么?  对 就是函数指针~~

    我们进入scheduleSelector看一下:
    void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, unsigned int repeat, float delay, bool bPaused)
    {
    。。。。。


    CCTimer *pTimer = new CCTimer();
    pTimer->initWithTarget(pTarget, pfnSelector, fInterval, repeat, delay);  //看这里
    ccArrayAppendObject(pElement->timers, pTimer);
    pTimer->release();
    }


    bool CCTimer::initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds, unsigned int nRepeat, float fDelay)
    {
    m_pTarget = pTarget;
    。。

    。。
    return true;
    }


    通过上面的代码能够看到。pTarget是传入的this。在哪里传入的呢 ?  在CCNode哟, 也就是说这里是传入的CCNode的对象哟。

    也就是说pTarget是CCNode对象。

    回滚回去。 这里pTarget是CCNode对象,他调用了selector,这里传入的是:m_pfnSelector
    你能够自己去CCNode的头文件和构造函数里去看一下。有这么两句:
    CCScheduler *m_pScheduler;          ///< scheduler used to schedule timers and updates
    m_pScheduler = director->getScheduler();

    有木有豁然开朗啊~~
    CCNode里面的m_pScheduler引用的是CCDirector的m_pScheduler哟。

    也就是说,先把m_pScheduler保存到CCNode里面,然后调用CCTimer的update的时候会运行到(m_pTarget->*m_pfnSelector)(m_fElapsed);在这里会调用CCNode的schedule两个函数,然后又会调用CCScheduler的scheduleSelector函数   又会进入到CCTimer的initWithTarget函数。


    上面的过程都是在CCDirector的mainLoop里面的。




    什么?你不知道函数指针是什么 ?  好吧~~看看这个(m_pTarget->*m_pfnSelector)(m_fElapsed);

    再来看一下函数指针:
    typedef void(*PF)(float);
    PF pF;
    void f(float a) {return;}

    pF = f;
    (*pF)(1);

    来比較一下:
    typedef void (CCObject::*SEL_SCHEDULE)(float);
    中间这个过程在代码里面都有分析哟
    (m_pTarget->*m_pfnSelector)(m_fElapsed);


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Entity Framework 批量操作
    Tsak多线程学习记录
    .net webservice 动态更换地址
    .NET EF Core2.0 (DBFirst)使用与配置
    MVC发布IIS后提示未配置默认文档
    未能加载文件或程序集“Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项。系统找不到指定的文件。
    Redis教程
    使用git将项目上传到github
    Redis集群(一)搭建Cluster模式[超简单]
    Redis 常见5大数据类型结构,附录3个数据类型
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4797777.html
Copyright © 2020-2023  润新知