0

I want to execute some codes with a time sequence like [5s, 10s, 10s, 20s], which means that it executes the code after 5 seconds, and executes it the second time after 10s. I want to use NSTimer, but I can not figure out how can I do.

lixiaoyu
  • 378
  • 5
  • 18

2 Answers2

0

Create a data structure to hold the time intervals, the target and the action to execute:

(untested)

typedef struct {
    NSTimeInterval interval;
    id target;
    SEL selector;
} ScheduledItem;

Then create an array of these items:

static ScheduledItem _schedule[] = {
    { 5.0, someTarget, @selector(someMethod) },
    { 10.0, someTarget, @selector(someMethod) },
    { 15.0, someTarget, @selector(someMethod) }
};
#define NUM_SCHEDULED_ITEMS (sizeof(schedule) / sizeof(schedule[0]))

and then create a timer somewhere to dispatch the work:

@interface MyClass ()
{
    NSTimer *_timer;
    unsigned _scheduledItem;
}
- (void)_setupTimer;
- (void)_timerFired:(NSTimer *)timer;
@end

@interface MyClass

- (instancetype)init
{
    self = [super init];
    if (self) {
        _scheduledItem = 0;
        [self _setupTimer];
    }
    return self;
}

- (void)_setupTimer
{
    _timer = nil;
    if (_scheduledItem < NUM_SCHEDULED_ITEMS) {
        NSTimeInterval interval = _schedule[_scheduledItem].interval
        _timer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                  target:self
                                                selector:@selector(_timerFired:)
                                                userInfo:nil
                                                 repeats:NO];
    }
}

- (void)_timerFired:(NSTimer *)timer
{
    id target = _schedule[_scheduledItem].target;
    SEL action = _schedule[_scheduleItem].action;
    [target performSelector:action withObject:nil];
    _scheduledItem++;
    [self _setupTimer];
}

You will most probably have to set-up the _schedule array at runtime, as the target won't be available at compile time. If it's always self then you can leave it out of the schedule altogether and if you always call the same selector then you can leave that out too, leaving just an array of time intervals.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
0

My method is a bit simpler to implement.

- (void)startExecute
  { 
    intervals=@[@(5),@(10),@(10),@(20)]; // class member
    isExecuting=YES; // class member
    [self executeTaskAtIndex:0]; // start first task
  }

- (void)executeTaskAtIndex:(NSUInteger)index
  { 
   if (index>=intervals.count || !isExecuting) // no intervals left or reset execution
       return;
   NSNumber *intervalNumber=intervals[index];
   NSTimeInterval interval=intervalNumber.doubleValue;
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
      if(!isExecuting)
         return;
      // execute your task here
      //...
      index++;
      [self executeTaskAtIndex:index]; // another iteration
   });
  }
Daniyar
  • 2,975
  • 2
  • 26
  • 39