jmasterx
jmasterx

Reputation: 54123

Good way to implement this?

Here is my need:

I'm making an ios app that controls a device. It has an API that lets me do things like:

turnOnLights()
turnOffLights()
rotate(degrees)
move(speed)

etc... (the api is completely objective c, im just giving an example in c synthax)

From this API, I need to build high level sequences, for example:

   turn on all lights
    wait 1 second
    turn off all lights
   wait 1 second

Or

move
rotate 30 degrees
wait 1 second
move
rotate -30 degrees

I can think of hacky ways to do these with timers, but I am wondering if ObjectiveC has a nice way that I could build some high level methods so I could for example:

ReturnValue flashLights()
ReturnValue moveAndRotate()

The idea behind this would be that, the commands needed to do the flashing action would be sent repeatedly forever, and, I can do:

stopAction(returnValue)

To stop it. (I know I'm writing in C synthax but I find it clearer to explain things).

So essentially, is there a convenient way to make a script-like thing where I can call a method that starts an action. The action makes method calls, waits some time, does more method calls, and repeats this forever until the action is stopped.

Thanks

Upvotes: 0

Views: 104

Answers (2)

David Schwartz
David Schwartz

Reputation: 508

Personally I don't think using an NSTimer would be 'hacky' as long as you implement it properly. You do need to make sure you invalidate the timer once you're finished with it though; check out this thread for more information about NSTimer best practices.

// in YourViewController.h
@property (nonatomic) BOOL flag;
@property (nonatomic, strong) NSTimer* timer;

// in YourViewController.m
-(void)viewDidLoad
{
    [super viewDidLoad];

    self.flag = YES;
    [self flashLights];

    // other code here
}

-(void)flashLights
{
    CGFloat interval = 1.0f;    // measured in seconds

    self.timer = [NSTimer scheduledTimerWithTimeInterval:interval 
                                                  target:self
                                                selector:@selector(timerEventHandler)
                                                userInfo:nil
                                                 repeats:YES];
}

-(void)timerEventHandler
{
    // your API calls might take a while to execute, so consider running them asynchronously:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
    {
        if (self.flag) turnOnLights();
        else turnOffLights();

        self.flag = !self.flag;
    });
}

-(void)stopAction
{
    [self.timer invalidate];
}

Upvotes: 0

Archy Will He
Archy Will He

Reputation: 9777

I am not sure if I understand your question properly, but if you want to repeatedly call a set of methods with delays in between, you can use aperformSelector:withObject:afterDelay, or dispatch_after to build a loop. (And there are many ways to leave the loop)

[self performSelector:@selector(resetIsBad) withObject:nil afterDelay:0.1];

or

int delayInSecond = 10;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delayInSecond * NSEC_PER_SEC), 
dispatch_get_main_queue(), ^{
   //doing something    
});

performSelector:withObject:afterDelay invokes a method of the receiver on the current thread using the default mode after a delay.

This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.

dispatch_after add your block to a queue and if the queue is empty, it runs immediately once being added to the queue. Else it will have to wait for other tasks in the queue to finish before it can run.

More on dispatch_after:

dispatch_after

Enqueue a block for execution at the specified time.

void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

Parameters:

when The temporal milestone returned by dispatch_time or dispatch_walltime.

queue The queue on which to submit the block. The queue is retained by the system until the block has run to completion. This parameter cannot be NULL.

block The block to submit. This function performs a Block_copy and Block_release on behalf of the caller. This parameter cannot be NULL.

Discussion

This function waits until the specified time and then asynchronously adds block to the specified queue.

Passing DISPATCH_TIME_NOW as the when parameter is supported, but is not as optimal as calling dispatch_async instead. Passing DISPATCH_TIME_FOREVER is undefined.

Declared In dispatch/queue.h

Upvotes: 1

Related Questions