非个人的全部理解,部分摘自cocos官网教程,感谢cocos官网。
在<CCScheduler.h>头文件中,定义了关于调度器的五个类:Timer,TimerTargetSelector,TimerTargetCallback, TimerScriptHandler和Scheduler,Timer和Scheduler直接继承于Ref类,TimerTargetSelector,TimerTargetCallback和TimerScriptHandler继承自Timer类。
先看看Timer类:
class CC_DLL Timer : public Ref
{
protected:
Timer();
public:
/** get interval in seconds */
inline float getInterval() const { return _interval; };
/** set interval in seconds */
inline void setInterval(float interval) { _interval = interval; };
void setupTimerWithInterval(float seconds, unsigned int repeat, float delay);
virtual void trigger() = 0;
virtual void cancel() = 0;
/** triggers the timer */
void update(float dt);
protected:
Scheduler* _scheduler; // weak ref
float _elapsed; // 渡过的时间
bool _runForever; // 标记是否永远运行
bool _useDelay; // 标记是否使用延迟
unsigned int _timesExecuted; // 记录已经执行了多少次
unsigned int _repeat; //0 = once, 1 is 2 x executed 定义要执行的次数,0表示执行1次, 1表示执行2次
float _delay; // 延迟的时间
float _interval; // 时间间隔
};
类中定义了一个Scheduler指针变量 _scheduler,根据注释可以看出,这是一个弱引用,弱引用不会增加它所引用的对象的引用计数;
根据分析Timer类的成员变量,可以知道这是一个用来描述计时器的类;
-
每隔 _interval 来触发一次;
-
_useDelay可以设置定时器触是否使用延迟; _delay是延迟时间;
-
_repeat可以设置定时器触发的次数; _runforever设置定时器永远执行。
然后看一下Timer类的update函数:
void Timer::update(float dt) //参数dt表示距离上一次update调用的时间间隔
{
if (_elapsed == -1)// 如果 _elapsed值为-1表示这个定时器是第一次进入到update方法 并做初始化操作。
{
_elapsed = 0;
_timesExecuted = 0;
}
else
{
if (_runForever && !_useDelay)
{//standard timer usage
_elapsed += dt; //累计渡过的时间。
if (_elapsed >= _interval)
{
trigger();
_elapsed = 0; //触发后将_elapsed清除为0,这里可能会有一小点的问题,因为 _elapsed值有可能大于_interval这里没有做冗余处理,所以会吞掉一些时间,比如 1秒执行一次,而10秒内可能执行的次数小于10,吞掉多少与update调用的频率有关系。
}
}
else
{//advanced usage
_elapsed += dt;
if (_useDelay)
{
if( _elapsed >= _delay )
{
trigger();
_elapsed = _elapsed - _delay;//延迟执行的计算
_timesExecuted += 1;
_useDelay = false; //延迟已经过了,清除_useDelay标记。
}
}
else
{
if (_elapsed >= _interval)
{
trigger();
_elapsed = 0;
_timesExecuted += 1;
}
}
if (!_runForever && _timesExecuted > _repeat)//触发的次数已经满足了_repeat的设置就取消定时器。
{ //unschedule timer
cancel();
}
}
}
}
在update函数里,调用了trigger和cancel函数,trigger是触发函数,cancel是取消定时器。
然后继续看<Scheduler.h>,是TimerTargetSelector,它继承自Timer:
class CC_DLL TimerTargetSelector : public Timer
{
public:
TimerTargetSelector();
/** Initializes a timer with a target, a selector and an interval in seconds, repeat in number of times to repeat, delay in seconds. */
bool initWithSelector(Scheduler* scheduler, SEL_SCHEDULE selector, Ref* target, float seconds, unsigned int repeat, float delay);
inline SEL_SCHEDULE getSelector() const { return _selector; };
virtual void trigger() override;
virtual void cancel() override;
protected:
Ref* _target; // 关联一个Ref对象,应该为执行定时器的对象
SEL_SCHEDULE _selector; // _selector是一个函数,是定时器触发时的回调函数
};
然后看看TimerTargetSelector的trigger和cancel函数,它重载了父类Timer的同名虚函数:
void TimerTargetSelector::trigger()
{
if (_target && _selector)
{
(_target->*_selector)(_elapsed);
}
}
void TimerTargetSelector::cancel()
{
_scheduler->unschedule(_selector, _target);
}
可以看出,在trigger中,执行了_selector这个回调函数,cancel函数则调用了unscheduler函数来结束,稍后分析。
继续看下一个类TimerTargetCallback:
class CC_DLL TimerTargetCallback : public Timer
{
public:
TimerTargetCallback();
/** Initialize