源代码版本号 3.1r,转载请注明
我也最终不out了,開始看3.x的源代码了。此时此刻的心情仅仅能是wtf!
!!!!!!!
!。只是也最终告别CC时代了。
cocos2d-x 源代码分析文件夹
        http://blog.csdn.net/u011225840/article/details/31743129
没错。是两张图。(你没有老眼昏花。
。我脑子也没有秀逗。。)Ref就是原来的CCObject。而Timer类是与Scheduler类密切相关的类,所以须要把他们放在一起说。Timer和Scheduler的关系就像Data和DataManager的关系。
//_elapsed 上一次运行后到如今的时间
	//timesExecuted 运行的次数
	//interval 运行间隔
	//useDelay 是否使用延迟运行
    float _elapsed;
    bool _runForever;
    bool _useDelay;
    unsigned int _timesExecuted;
    unsigned int _repeat; //0 = once, 1 is 2 x executed
    float _delay;
    float _interval;void Timer::update(float dt)
{
	//update方法使用的是模板设计模式,将trigger与cancel的实现交给子类。
	
    if (_elapsed == -1)
    {
        _elapsed = 0;
        _timesExecuted = 0;
    }
	//四种情况
	/*
		1.永久运行而且不使用延迟:基本使用方法。计算elapsed大于interval后运行一次,永不cancel。
		2.永久运行而且使用延迟:当elapsed大于延迟时间后,运行一次后,进入情况1.
		3.不永久运行而且不使用延迟:情况1结束后,会推断运行次数是否大于反复次数,大于后则cancel。
		4.不永久运行而且使用延迟:情况2结束后,进入情况3.
	*/
    else
    {
        if (_runForever && !_useDelay)
        {//standard timer usage
            _elapsed += dt;
            if (_elapsed >= _interval)
            {
                trigger();
                _elapsed = 0;
            }
        }    
        else
        {//advanced usage
            _elapsed += dt;
            if (_useDelay)
            {
                if( _elapsed >= _delay )
                {
                    trigger();
                    
                    _elapsed = _elapsed - _delay;
                    _timesExecuted += 1;
                    _useDelay = false;
                }
            }
            else
            {
                if (_elapsed >= _interval)
                {
                    trigger();
                    
                    _elapsed = 0;
                    _timesExecuted += 1;
                }
            }
            if (!_runForever && _timesExecuted > _repeat)
            {    //unschedule timer
                cancel();
            }
        }
    }
}           正如我凝视中所说,update使用了模板方法的设计模式思想。将trigger与cancel调用的过程写死,可是不同的子类实现trigger和cancel的方式不同。void TimerTargetSelector::trigger()
{
    if (_target && _selector)
    {
        (_target->*_selector)(_elapsed);
    }
}
void TimerTargetCallback::trigger()
{
    if (_callback)
    {
        _callback(_elapsed);
    }
}    Ref* _target;
    SEL_SCHEDULE _selector;
 ------  ------------------------
    void* _target;
    ccSchedulerFunc _callback;
    std::string _key;typedef struct _hashSelectorEntry
{
    ccArray             *timers;
    void                *target;
    int                 timerIndex;
    Timer               *currentTimer;
    bool                currentTimerSalvaged;
    bool                paused;
    UT_hash_handle      hh;
} tHashTimerEntry;在这个结构里,target是key值,其它都是数据(除了hh哦)。
timers存放着该target相关的全部timer。currentTimerSalvaged的作用是假设你想停止unschedule正在运行的timer时。会将其从timers移除。并retain,防止被自己主动回收机制回收。然后将此标识为true。以下来看下第一种TimerCallback的Schedule。
void Scheduler::schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key)
{
    CCASSERT(target, "Argument target must be non-nullptr");
    CCASSERT(!key.empty(), "key should not be empty!");
	//先在hash中查找该target(key值)是否已经有数据
    tHashTimerEntry *element = nullptr;
    HASH_FIND_PTR(_hashForTimers, &target, element);
	//没有就创建一个。而且将其加入
    if (! element)
    {
        element = (tHashTimerEntry *)calloc(sizeof(*element), 1);
        element->target = target;
        HASH_ADD_PTR(_hashForTimers, target, element);
        // Is this the 1st element ? Then set the pause level to all the selectors of this target
        element->paused = paused;
    }
    else
    {
        CCASSERT(element->paused == paused, "");
    }
	//第一次创建target的数据。需要将timers初始化
    if (element->timers == nullptr)
    {
        element->timers = ccArrayNew(10);
    }
    else 
    {
		//在timers中查找timer,看在该target下的全部timer绑定的key值是否存在,假设存在,设置新的interval后返回。
		//这里必需要解释下,target是hash表的key值。用来查找timers等数据。
		//而TimerCallback类型的timer本身含有一个key值(std::string类型),用来标识该唯一timer
        for (int i = 0; i < element->timers->num; ++i)
        {
            TimerTargetCallback *timer = static_cast<TimerTargetCallback*>(element->timers->arr[i]);
            if (key == timer->getKey())
            {
                CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), interval);
                timer->setInterval(interval);
                return;
            }        
        }
        ccArrayEnsureExtraCapacity(element->timers, 1);
    }
	//假设TimerCallback原本不存在在timers中。就加入新的
    TimerTargetCallback *timer = new TimerTargetCallback();
    timer->initWithCallback(this, callback, target, key, interval, repeat, delay);
    ccArrayAppendObject(element->timers, timer);
    timer->release();
} if (selector == timer->getSelector())
            {
                CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), interval);
                timer->setInterval(interval);
                return;
            }void Scheduler::unschedule(SEL_SCHEDULE selector, Ref *target)
{
    // explicity handle nil arguments when removing an object
    if (target == nullptr || selector == nullptr)
    {
        return;
    }
    
    //CCASSERT(target);
    //CCASSERT(selector);
    
    tHashTimerEntry *element = nullptr;
    HASH_FIND_PTR(_hashForTimers, &target, element);
    //假设该target存在数据,就进行删除操作。
    if (element)
    {
		//遍历寻找
        for (int i = 0; i < element->timers->num; ++i)
        {
            TimerTargetSelector *timer = static_cast<TimerTargetSelector*>(element->timers->arr[i]);
            //假设正在运行的Timer是须要被unschedule的timer,将其移除而且标识当前正在运行的Timer须要被移除状态为true。
            if (selector == timer->getSelector())
            {
                if (timer == element->currentTimer && (! element->currentTimerSalvaged))
                {
                    element->currentTimer->retain();
                    element->currentTimerSalvaged = true;
                }
                
                ccArrayRemoveObjectAtIndex(element->timers, i, true);
                
                // update timerIndex in case we are in tick:, looping over the actions
                if (element->timerIndex >= i)
                {
                    element->timerIndex--;
                }
                
				//当前timers中不再含有timer。可是假设正在运行的target是该target,则将正在运行的target将被清除标识为true
				//否则,能够直接将其从hash中移除
                if (element->timers->num == 0)
                {
                    if (_currentTarget == element)
                    {
                        _currentTargetSalvaged = true;
                    }
                    else
                    {
                        removeHashElement(element);
                    }
                }
                
                return;
            }
        }
    }
}
(此外。模式2还引入了优先级的概念)
  template <class T>
    void scheduleUpdate(T *target, int priority, bool paused)
    {
        this->schedulePerFrame([target](float dt){
            target->update(dt);
        }, target, priority, paused);
    }// A list double-linked list used for "updates with priority"
typedef struct _listEntry
{
    struct _listEntry   *prev, *next;
    ccSchedulerFunc     callback;
    void                *target;
    int                 priority;
    bool                paused;
    bool                markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
} tListEntry;
typedef struct _hashUpdateEntry
{
    tListEntry          **list;        // Which list does it belong to ?
    tListEntry          *entry;        // entry in the list
    void                *target;
    ccSchedulerFunc     callback;
    UT_hash_handle      hh;
} tHashUpdateEntry;
能够注意到。HashEntry中有个List,来表示该entry属于哪个list。在scheduler中,一共同拥有三个updateList,依据优先级分为negativeList,0List,positiveList,值越小越先运行。
void Scheduler::schedulePerFrame(const ccSchedulerFunc& callback, void *target, int priority, bool paused)
{
	//先检查hash中是否存在该target,假设存在,则将其deleteion的标识 置为false后返回。(可能某个操作将其置为true。而且
	//scheduler还没来得及删除,所以这里仅仅须要再改为false就可以)
    tHashUpdateEntry *hashElement = nullptr;
    HASH_FIND_PTR(_hashForUpdates, &target, hashElement);
    if (hashElement)
    {
#if COCOS2D_DEBUG >= 1
        CCASSERT(hashElement->entry->markedForDeletion,"");
#endif
        // TODO: check if priority has changed!
        hashElement->entry->markedForDeletion = false;
        return;
    }
    // most of the updates are going to be 0, that's way there
    // is an special list for updates with priority 0
	//英文凝视解释了为啥有一个0List。
    if (priority == 0)
    {
        appendIn(&_updates0List, callback, target, paused);
    }
    else if (priority < 0)
    {
        priorityIn(&_updatesNegList, callback, target, priority, paused);
    }
    else
    {
        // priority > 0
        priorityIn(&_updatesPosList, callback, target, priority, paused);
    }
}
void Scheduler::appendIn(_listEntry **list, const ccSchedulerFunc& callback, void *target, bool paused)
{
	//为该target新建一个listEntry
    tListEntry *listElement = new tListEntry();
    listElement->callback = callback;
    listElement->target = target;
    listElement->paused = paused;
    listElement->markedForDeletion = false;
    DL_APPEND(*list, listElement);
    // update hash entry for quicker access
	//而且为该target建立一个高速存取的target
    tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
    hashElement->target = target;
    hashElement->list = list;
    hashElement->entry = listElement;
    HASH_ADD_PTR(_hashForUpdates, target, hashElement);
}void Scheduler::priorityIn(tListEntry **list, const ccSchedulerFunc& callback, void *target, int priority, bool paused)
{
	//同理,为target建立一个entry
    tListEntry *listElement = new tListEntry();
    listElement->callback = callback;
    listElement->target = target;
    listElement->priority = priority;
    listElement->paused = paused;
    listElement->next = listElement->prev = nullptr;
    listElement->markedForDeletion = false;
    // empty list ?
    if (! *list)
    {
        DL_APPEND(*list, listElement);
    }
    else
    {
        bool added = false;
		//依据优先级。将element放在一个合适的位置,标准的有序链表插入操作,不多解释。
        for (tListEntry *element = *list; element; element = element->next)
        {
            if (priority < element->priority)
            {
                if (element == *list)
                {
                    DL_PREPEND(*list, listElement);
                }
                else
                {
                    listElement->next = element;
                    listElement->prev = element->prev;
                    element->prev->next = listElement;
                    element->prev = listElement;
                }
                added = true;
                break;
            }
        }
        // Not added? priority has the higher value. Append it.
        if (! added)
        {
            DL_APPEND(*list, listElement);
        }
    }
    // update hash entry for quick access
    tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
    hashElement->target = target;
    hashElement->list = list;
    hashElement->entry = listElement;
    HASH_ADD_PTR(_hashForUpdates, target, hashElement);
}
 //
    // "updates with priority" stuff
    //
    struct _listEntry *_updatesNegList;        // list of priority < 0
    struct _listEntry *_updates0List;            // list priority == 0
    struct _listEntry *_updatesPosList;        // list priority > 0
    struct _hashUpdateEntry *_hashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etcvoid Scheduler::unscheduleUpdate(void *target)
{
	
    if (target == nullptr)
    {
        return;
    }
    tHashUpdateEntry *element = nullptr;
    HASH_FIND_PTR(_hashForUpdates, &target, element);
    if (element)
    {
        if (_updateHashLocked)
        {
            element->entry->markedForDeletion = true;
        }
        else
        {
            this->removeUpdateFromHash(element->entry);
        }
    }
}update函数会在后面介绍,以下,继续看unschedule的其它方法。
void Scheduler::unscheduleAllForTarget(void *target)
{
    // explicit nullptr handling
    if (target == nullptr)
    {
        return;
    }
    // Custom Selectors
    tHashTimerEntry *element = nullptr;
    HASH_FIND_PTR(_hashForTimers, &target, element);
    if (element)
    {
        if (ccArrayContainsObject(element->timers, element->currentTimer)
            && (! element->currentTimerSalvaged))
        {
            element->currentTimer->retain();
            element->currentTimerSalvaged = true;
        }
        ccArrayRemoveAllObjects(element->timers);
        if (_currentTarget == element)
        {
            _currentTargetSalvaged = true;
        }
        else
        {
            removeHashElement(element);
        }
    }
    // update selector
    unscheduleUpdate(target);
}         该方法会移除target相关的全部定时。包含update类型的,包含Custom Selector类型的,和其它的一样,须要注意该标志位。void Scheduler::update(float dt)
{
    _updateHashLocked = true;
	//timeScale是什么意思呢,正常的速度是1.0,假设你想二倍速放就设置成2.0,假设你想慢慢放。就设置成0.5.
    if (_timeScale != 1.0f)
    {
        dt *= _timeScale;
    }
    //
    // Selector callbacks
    //
    // Iterate over all the Updates' selectors
    tListEntry *entry, *tmp;
	//首先处理update类型的定时,你能够发现想调用它的callback,必须满足markedForDeletion为false,从而证明我上面的说法。
    // updates with priority < 0
    DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
    {
        if ((! entry->paused) && (! entry->markedForDeletion))
        {
            entry->callback(dt);
        }
    }
    // updates with priority == 0
    DL_FOREACH_SAFE(_updates0List, entry, tmp)
    {
        if ((! entry->paused) && (! entry->markedForDeletion))
        {
            entry->callback(dt);
        }
    }
    // updates with priority > 0
    DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
    {
        if ((! entry->paused) && (! entry->markedForDeletion))
        {
            entry->callback(dt);
        }
    }
	//处理custom类型的定时
    // Iterate over all the custom selectors
    for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )
    {
        _currentTarget = elt;
        _currentTargetSalvaged = false;
		//没有被暂停。则能够处理
        if (! _currentTarget->paused)
        {
            // The 'timers' array may change while inside this loop
			//循环内是当前target下的全部Timer
            for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
            {
                elt->currentTimer = (Timer*)(elt->timers->arr[elt->timerIndex]);
                elt->currentTimerSalvaged = false;
                elt->currentTimer->update(dt);
				//假设currentTimer的update本身内部。在一定条件下unSchedule了本身,则会改变currentTimerSalvaged的标识信息。
				//所以要再次进行推断,这就是循环上面英文凝视所述之意
                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 = nullptr;
            }
        }
        // elt, at this moment, is still valid
        // so it is safe to ask this here (issue #490)
        elt = (tHashTimerEntry *)elt->hh.next;
        // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
		//即使在大循环開始时_currentTargetSalvaged被设置为false。如今的值也可能由于上面该target的各种定时函数调用导致其为true
        if (_currentTargetSalvaged && _currentTarget->timers->num == 0)
        {
            removeHashElement(_currentTarget);
        }
    }
	//这些update类型的定时要被删除咯~~
    // delete all updates that are marked for deletion
    // updates with priority < 0
    DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
    {
        if (entry->markedForDeletion)
        {
            this->removeUpdateFromHash(entry);
        }
    }
    // updates with priority == 0
    DL_FOREACH_SAFE(_updates0List, entry, tmp)
    {
        if (entry->markedForDeletion)
        {
            this->removeUpdateFromHash(entry);
        }
    }
    // updates with priority > 0
    DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
    {
        if (entry->markedForDeletion)
        {
            this->removeUpdateFromHash(entry);
        }
    }
    _updateHashLocked = false;
    _currentTarget = nullptr;
}所以在每次循环之后,都会推断这些状态位,假设被改变,须要做什么操作。
在代码凝视中,我已经说明。
就是更改状态而已。。
Cocos2d-x 源代码分析 : Scheduler(定时器) 源代码分析
原文:http://www.cnblogs.com/jhcelue/p/7359219.html