更多的时候为了省事,我们都将std::function的那一长串东西用一个auto代替。通过上面的例子就说明了lambda返回的类型也是需要std::function接收的,通过上面的例子我们得出这样的结论,如果要回调某一个函数,就像菜单的回调,按钮的回调,schedule的回调,CCallFunc动作序列,我们可以传入函数指针+调用对象target,或者使用std::function,而std::function可以通过std::bind绑定获得,或者通过lambda表达式获得。
接下来看一下回调函数在schedule中是如何应用的。
2
->schedule(SEL_SCHEDULE(&HelloWorld::call),1.0f);
->schedule(schedule_selector(HelloWorld::call),1.0f);
|
以下的两种调用方式道理都是一样的,仔细比较一下发现使用SEL_SCHEDULE需要加一个取地址符,使用schedule_selector不需要,原因看下各自的定义大家就明白了。SEL_SCHEDULE直接就是函数指针,而schedule_selector是个宏定义,传入里边的参数,用static_cast转化为SEL_SCHEDULE类型的时候加上了取地址符。这里把这个基础的问题说下,也是对C++的一种复习吧!
2
typedef
(Ref::*SEL_SCHEDULE)(
float
);
#defineschedule_selector(_SELECTOR)static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)
|
我们发现一个问题,用这种方法做回调的时候,不是需要传入一个target吗,为什么这种方法没有传入这个target,或者说是this参数,我们只好翻翻源码了,那就一步步跟进源码,跟到这里(代码在下边)的时候发现了用变量_schedule调用了一个schedule函数,这个_schedule是什么,我们在文件中查找一下,发现_scheduler = director->getScheduler();原来它是通过Director获得的,其实它的类型是Scheduler,这个东西是一个单例,在Director类中保持着对这个单利对象的引用。同时这个schedule函数的第二个参数就是this,而这个this就是我们要得target,所以这就说明这个target不是没有传入,而是在引擎的内部传入了this!
6
7
Node::schedule(SEL_SCHEDULEselector,
interval,unsigned
int
repeat,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">delay)
{
CCASSERT(selector,monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"Argumentmustbenon-nil"
CCASSERT(interval>=0,monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"Argumentmustbepositive"
);
_scheduler->schedule(selector,interval,repeat,delay,!_running);
}
|
我们继续跟进schedule函数,发现文件跳到了Scheduler类中,调用了Scheduler类的schedule,到这里所有的东西就明白了。我们在类中调用schedule,表面上调用的是Node类的schedule,其实最后调用的是Scheduler类中得schedule函数。我们所说的第一种形式的回调this的传入是在node类中转调用scheduler中的schedule的时候帮我们传入了this。最后有必要看一下这个schedule的声明。
Scheduler::schedule(SEL_SCHEDULEselector,Ref*target,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">delay,monospace!important; font-size:1em!important; min-height:auto!important; color:gray!important; background:none!important">bool
paused)
那我们想要的第二种回调的形式呢?我找了Node的整个schedule函数都没有发现,因为Node最终还是调用的scheduler类的函数,所以我们去scheduler类中找一找,果然,我发现了采用第二种回调形式的schedule函数,声明如下。
1
Scheduler::schedule(
const
ccSchedulerFunc&callback,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">*target,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">paused,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">std::string&key)
|
我们跟进去看一下ccSchedulerFunc的定义,如下:
1
typedef
(
)>ccSchedulerFunc;
|
怎么样,一个std::function出来了吧,但是Node中却没有提供给我们这样的schedule函数调用,有如此简单的调用形式却不用岂不是可惜?那我们要怎么办?很简单,直接使用Scheduler中得函数不就可以了。所以采用第二种回调方式的调用方法如下。
2
auto_schedule=Director::getInstance()->getScheduler();
_schedule->schedule([](
float
tm
){
"%f"
);},1.0f,!
->isRunning(),monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"xiaota"
);
|
现在,我们可以尽情的使用lambda表达式了,省去了麻烦的函数头文件声明,这几个参数很简单是类似于普通的schedule函数,只是最后一个参数要注意一下,他是一个string类型,这个string类型有什么作用呢?我们让schedule跑了起来,停的时候该怎么办呢?对,就是用的这个string,当然还有第二个参数target,所以这里你传入的这个key值必须和其他的key值保持不同,否则的话停掉的时候就出错了。这个原因估计也是引擎组没有将这个接口放到Node中得因素吧!现在schedule的用法和小小的分析就到这里结束了,大家如果发现有什么错误之处还请指正!
来源网址:http://www.cocoachina.com/bbs/read.php?tid=217556
原文链接:https://www.f2er.com/cocos2dx/341497.html