public void unscheduleBlockForKey(string key, System.Object target)
        {
            // explicity handle nil arguments when removing an object
            if (target == null && key == null)
            {
                return;
            }

            NSUtils.Assert(target != null, "Target MUST not be nil");
            NSUtils.Assert(key != null, "key MUST not be NULL");

            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());

            if (element != null)
            {
                for (int i = 0; i < element.timers.Count; i++)
                {
                    CCTimer timer = element.timers[i];


                    if (timer is CCTimerBlock && key == ((CCTimerBlock)timer).key)
                    {
                        if (timer == element.currentTimer && !element.currentTimerSalvaged)
                        {
                            element.currentTimerSalvaged = true;
                        }

                        element.timers.RemoveAt(i);

                        // update timerIndex in case we are in tick:, looping over the actions
                        if (element.timerIndex >= i)
                        {
                            element.timerIndex--;
                        }

                        if (element.timers.Count == 0)
                        {
                            if (currentTarget == element)
                            {
                                currentTargetSalvaged = true;
                            }
                            else
                            {
                                removeHashElement(element);
                            }
                        }
                        return;
                    }
                }
            }
            // Not Found
            //	NSLog(@"CCScheduler#unscheduleSelector:forTarget: selector not found: %@", selString);
        }
        /** Unshedules a selector for a given target.
         * If you want to unschedule the "update", use unscheudleUpdateForTarget.
         * @since v0.99.3
         */
        public void unscheduleSelector(TICK_IMP selector, System.Object target)
        {
            if (target == null && selector == null)
            {
                return;
            }

            NSUtils.Assert(target != null, "Target MUST not be nil");
            NSUtils.Assert(selector != null, "Selector MUST not be NULL");

            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());

            if (element != null)
            {
                int timersCount = element.timers.Count;
                for (int i = 0; i < timersCount; i++)
                {
                    CCTimer timer = element.timers[i];
                    if (timer is CCTimerTargetSelector && selector == ((CCTimerTargetSelector)timer).selector)
                    {
                        if (timer == element.currentTimer && !element.currentTimerSalvaged)
                        {
                            element.currentTimerSalvaged = true;
                        }
                        element.timers.RemoveAt(i);
                        if (element.timerIndex >= i)
                        {
                            element.timerIndex--;
                        }
                        if (element.timers.Count == 0)
                        {
                            if (currentTarget == element)
                            {
                                currentTargetSalvaged = true;
                            }
                            else
                            {
                                removeHashElement(element);
                            }
                        }
                        return;
                    }
                }
            }

            // Not Found
            //	NSLog(@"CCScheduler#unscheduleSelector:forTarget: selector not found: %@", selString);
        }
        public void scheduleBlockForKey(string key, System.Object owner, float interval, uint repeat, float delay, bool paused, TICK_IMP block)
        {
            NSUtils.Assert(block != null, "Argument block must be non-nil");
            NSUtils.Assert(owner != null, "Argument owner must be non-nil");

            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(owner.GetHashCode());

            if (element == null)
            {
                element        = new tHashTimerEntry();
                element.target = owner;
                hashForTimers.HASH_ADD_INT(owner.GetHashCode(), element);

                // Is this the 1st element ? Then set the pause level to all the selectors of this target
                element.paused = paused;
            }
            else
            {
                NSUtils.Assert(element.paused == paused, "CCScheduler. Trying to schedule a block with a pause value different than the target");
            }


            if (element.timers == null)
            {
                element.timers = new List <CCTimer> (10);
            }
            else
            {
                var enumerator = element.timers.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    CCTimer timer = enumerator.Current;
                    if (timer is CCTimerBlock && key == ((CCTimerBlock)timer).key)
                    {
                        CCDebug.Log("CCScheduler#scheduleBlock. Block already scheduled. Updating interval from: {0:0.0000} to {1:0.0000}", timer.interval, interval);
                        timer.interval = interval;
                        return;
                    }
                }
            }

            CCTimerBlock timerBlock = new CCTimerBlock(owner, interval, key, block, repeat, delay);

            element.timers.Add(timerBlock);
        }
        /** 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 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 lets 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
         */
        public void schedule(TICK_IMP selector, System.Object target, float interval, uint repeat, bool paused, float delay = 0)
        {
            NSUtils.Assert(selector != null, "Argument selector must be non-nil");
            NSUtils.Assert(target != null, "Argument target must be non-nil");

            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());

            if (element == null)
            {
                element        = new tHashTimerEntry();
                element.target = target;
                hashForTimers.HASH_ADD_INT(target.GetHashCode(), element);

                // Is this the 1st element ? Then set the pause level to all the selectors of this target
                element.paused = paused;
            }
            else
            {
                NSUtils.Assert(element.paused == paused, "CCScheduler. Trying to schedule a selector with a pause value different than the target");
            }


            if (element.timers == null)
            {
                element.timers = new List <CCTimer> (10);
            }
            else
            {
                var enumerator = element.timers.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    CCTimer timer = enumerator.Current;
                    if (timer is CCTimerTargetSelector && selector == ((CCTimerTargetSelector)timer).selector)
                    {
                        CCDebug.Log("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: {0:0.0000} to {1:0.0000}", timer.interval, interval);
                        timer.interval = interval;
                        return;
                    }
                }
            }
            CCTimerTargetSelector timerSelector = new CCTimerTargetSelector(target, selector, interval, repeat, delay);

            element.timers.Add(timerSelector);
        }