在上一篇的第二部分中。我们有一句代码待解释的:
// 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);

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

cocos2dx 解释二具体的启动过程:内存管理和回调的更多相关文章

  1. linux源码分析(二)-启动过程

    前置:这里使用的linux版本是4.8,x86体系. 这篇是 http://home.ustc.edu.cn/~boj/courses/linux_kernel/1_boot.html 的学习笔记. ...

  2. Angular总结二:Angular 启动过程

    要弄清楚 Angular 的启动过程,就要弄明白 Angular 启动时加载了哪个页面,加载了哪些脚本,这些脚本做了哪些事? 通过 Angular 的编译依赖文件 .angular-cli.json ...

  3. (二)SpringBoot启动过程的分析-环境信息准备

    -- 以下内容均基于2.1.8.RELEASE版本 由上一篇SpringBoot基本启动过程的分析可以发现在run方法内部启动SpringBoot应用时采用多个步骤来实现,本文记录启动的第二个环节:环 ...

  4. 【cocos2d-x 3.x 学习笔记】对象内存管理

    内存管理 内存管理一直是一个不易处理的问题.开发人员必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理,等等.内存管理的核心是动态分配的对象必须保证在使用完成后有效地释放内存,即管理对象的生命周 ...

  5. 二、Linux文件系统之内存管理

    虚拟内存  32位:4G 64位:2^64 内存管理: 进程管理 自动分配和管理 支持模块化程序设计 保护和访问控制 长期存储 虚拟内存  <---MMU-->物理内存

  6. LinearLayout具体解释二:LinearLayout的创建过程以及状态全程解析

    正在撰稿中,请稍等...

  7. springboot启动过程中常用的回调

    1.介绍 springboot提供非常丰富回调接口,利用这些接口可以做非常多的事情,对于一些常用的回调接口进行介绍 2.常用的拓展接口 1.ApplicationContextInitializer ...

  8. Android(java)学习笔记162:Android启动过程(转载)

    转载路径为: http://blog.jobbole.com/67931/ 1. 关于Android启动过程的问题: 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样 ...

  9. Android程序启动过程深入解析

    当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样的? 什么是Linux内核? 桌面系统linux内核与Android系统linux内核有什么区别? 什么是引导装载程序 ...

随机推荐

  1. 基数排序---Java实现+C++实现

    基数排序是基于桶排序实现的,总之基本思想是:先基于个位进行桶排序,更新原序列:再基于十位进行桶排序,更新原序列-- code1:java import java.util.*; public clas ...

  2. 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)

    原文:乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) 作者:weba ...

  3. Oracle 工艺结构

    Oracle工艺结构 这个过程是动态创建,完毕任务后就消亡:而程序是静态的实体,程序是能够复制.编辑的.进程强调的是运行过程,而程序不过指令的有序集合:进程在内存中,程序在外存中. ORACLE分为用 ...

  4. 1.网络工具:ifconfig,ping,netstate,Redhat命令和图形化设置ip,finger,nslookup

     1 ip ad查看网卡编号 2.ifconfig查看网卡信息 3.关闭网卡 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcX ...

  5. 苹果WatchKit轻松入门

    背景 前段时间苹果Apple推出 WatchKit,用于开发Apple Watch应用,同时也推出了 Xcode6.2 Beta(非稳定版,好期待稳定版)版本用于开发 Watch App.Apple ...

  6. 【剑指offer】面试题28:弦乐

    def Permutation(data, i): if len( data ) == 0: return # i stand for the start of first part for i in ...

  7. UVa11488-Hyper Prefix Sets(trie树)

    H Hyper Prefix Sets Prefix goodness of a set string is length of longest common prefix*number of str ...

  8. Java于 初始化序列?

    我们正处于java于 Java中初始化的顺寻? java代码: package sru.love.c; class Person { String name = "Person"; ...

  9. Android开发学习总结——Android开发的一些相关概念(转)

    一.什么是3G.4G 1995年问世的第一代模拟制式手机(1G)只能进行语音通话. 1996到1997年出现的第二代GSM.CDMA等数字制式手机(2G)便增加了接收数据的功能 Ÿ 3G指的是第三代移 ...

  10. 使用Canvas和Paint自己绘制折线图

    主要用于Canvas一个特别简单的小demo. 能够手动点击看每一个月份的数据.很easy.就是用paint在canvas上画出来的. 主要内容就是计算左边价格的位置,以下日期的位置,三根虚线的位置, ...