时间间隔定时器分析
- 1、//存放时间间隔定时器的结构
- // Hash Element used for "selectors with interval"
- typedef struct _hashSelectorEntry
- {
- ccArray *timers; //注:一个Target(如CCNode)中可能会添加多个时间间隔不同的定时器,
- //因为属于同一个Target,只有一个tHashTimerEntry结构,
- //但是时间间隔不同,回调不同的函数,所以
- //需要存放在一个数组中,数组中的元素类型是CCTimer,后面分析
- CCObject *target; // hash key (retained)
- unsigned int timerIndex;
- CCTimer *currentTimer;
- bool currentTimerSalvaged;
- bool paused;
- UT_hash_handle hh;
- } tHashTimerEntry;
- 注:在CCScheduler中,有一个成员变量,用于存放这种结构的哈希表
- // Used for "selectors with interval"
- struct _hashSelectorEntry *m_pHashForTimers;
- 2、添加时间间隔定时器
- /** The scheduled method will be called every 'interval' seconds.
- If paused is YES,then it won't be called until it is resumed.
- If 'interval' is 0,it will be called every frame,but if so,it's recommended to use 'scheduleUpdateForTarget:' instead.
- If the selector is already scheduled,then only the interval parameter will be updated without re-scheduling it again.
- repeat let the action be repeated repeat + 1 times,use kCCRepeatForever to let the action run continuously
- delay is the amount of time the action will wait before it'll start
- @since v0.99.3,repeat and delay added in v1.1
- @js NA
- @lua NA
- */
- void scheduleSelector(SEL_SCHEDULE pfnSelector,CCObject *pTarget,float fInterval,unsigned int repeat,float delay,bool bPaused);
- -->>
- void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector,bool bPaused)
- {
- CCAssert(pfnSelector,"Argument selector must be non-NULL");
- CCAssert(pTarget,"Argument target must be non-NULL");
- //同一个Target只会有一个tHashTimerEntry结构
- tHashTimerEntry *pElement = NULL;
- HASH_FIND_INT(m_pHashForTimers,&pTarget,pElement);
- //如果不存在,则新增加一个
- if (! pElement)
- {
- pElement = (tHashTimerEntry *)calloc(sizeof(*pElement),1);
- pElement->target = pTarget;
- if (pTarget)
- {
- pTarget->retain(); //对对象执行一次retain操作
- }
- //添加到m_pHashForTimers哈希表中
- HASH_ADD_INT(m_pHashForTimers,target,pElement);
- // Is this the 1st element ? Then set the pause level to all the selectors of this target
- pElement->paused = bPaused;
- }
- else
- {
- CCAssert(pElement->paused == bPaused,"");
- }
- //同一个Target,如果有多个不同的定时器,存放到一个数组中
- if (pElement->timers == NULL)
- {
- pElement->timers = ccArrayNew(10);
- }
- else
- {
- //如果某个pfnSelector回调函数已经存在,则只修改定时器的时间间隔
- for (unsigned int i = 0; i < pElement->timers->num; ++i)
- {
- CCTimer *timer = (CCTimer*)pElement->timers->arr[i];
- if (pfnSelector == timer->getSelector())
- {
- CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f",timer->getInterval(),fInterval);
- timer->setInterval(fInterval);
- return;
- }
- }
- ccArrayEnsureExtraCapacity(pElement->timers,1);
- }
- //如果pfnSelector回调函数第一次加入,则创建一个CCTimer,并初始化
- CCTimer *pTimer = new CCTimer();
- pTimer->initWithTarget(pTarget,pfnSelector,fInterval,repeat,delay);
- ccArrayAppendObject(pElement->timers,pTimer);
- pTimer->release();
- }
- 3、移除时间间隔定时器
- /** Unschedule a selector for a given target.
- If you want to unschedule the "update",use unscheudleUpdateForTarget.
- @since v0.99.3
- @lua NA
- */
- void unscheduleSelector(SEL_SCHEDULE pfnSelector,CCObject *pTarget);
- -->>源码:
- void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector,CCObject *pTarget)
- {
- // explicity handle nil arguments when removing an object
- if (pTarget == 0 || pfnSelector == 0)
- {
- return;
- }
- //CCAssert(pTarget);
- //CCAssert(pfnSelector);
- tHashTimerEntry *pElement = NULL;
- HASH_FIND_INT(m_pHashForTimers,pElement);
- if (pElement)
- {
- for (unsigned int i = 0; i < pElement->timers->num; ++i)
- {
- CCTimer *pTimer = (CCTimer*)(pElement->timers->arr[i]);
- //把存放pfnSelector的CCTimer移除
- if (pfnSelector == pTimer->getSelector())
- {
- if (pTimer == pElement->currentTimer && (! pElement->currentTimerSalvaged))
- {
- pElement->currentTimer->retain();
- pElement->currentTimerSalvaged = true;
- }
- ccArrayRemoveObjectAtIndex(pElement->timers,i,true);
- // update timerIndex in case we are in tick:,looping over the actions
- if (pElement->timerIndex >= i)
- {
- pElement->timerIndex--;
- }
- //如果CCTimer数量为0,则移除tHashTimerEntry结构
- if (pElement->timers->num == 0)
- {
- if (m_pCurrentTarget == pElement)
- {
- m_bCurrentTargetSalvaged = true;
- }
- else
- {
- removeHashElement(pElement);
- }
- }
- return;
- }
- }
- }
- }
- -->>
- void CCScheduler::removeHashElement(_hashSelectorEntry *pElement)
- {
- cocos2d::CCObject *target = pElement->target;
- ccArrayFree(pElement->timers);
- HASH_DEL(m_pHashForTimers,pElement);
- free(pElement);
- // make sure the target is released after we have removed the hash element
- // otherwise we access invalid memory when the release call deletes the target
- // and the target calls removeAllSelectors() during its destructor
- target->release(); //对target对象执行一次release
- }