user2255273
user2255273

Reputation: 958

Objective C - Run method multiple times, when finished run another method

I have two methods that both create a random sprite node and add it to the scene. Let's call them spriteMethod1 and spriteMethod2.

I'd like to have a looping method that runs spriteMethod1, 5 times, and then spriteMethod2 once. There also needs to be a delay between each time the spriteMethods are called.

I thought the following might work, but it doesn't:

-(void) addObjects {
    for (int i = 0; i < 5; i++) {
        [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:2];
    }
    [self performSelector:@selector(spriteMethod2) withObject:nil afterDelay:3];
    [self performSelector:@selector(addObjects) withObject:nil afterDelay:5];
}

Upvotes: 3

Views: 1840

Answers (5)

Basheer_CAD
Basheer_CAD

Reputation: 4919

Add a timer in your interface:

@property (nonatomic, weak) NSTimer *timer;

schedule a timer somewhere in your code

self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(spriteMethod1) userInfo:nil repeats:YES];

do this

int count = 0;

- (void)spriteMethod1 {
        count ++;
        // do your work here

        if(count == 5) {
            // stop the timer
            [self.timer invalidate];

            // call the other methods
            [self performSelector:@selector(spriteMethod2) withObject:nil afterDelay:3];
            [self performSelector:@selector(addObjects) withObject:nil afterDelay:5];
        }
    }

Upvotes: 1

Janis Kirsteins
Janis Kirsteins

Reputation: 2138

I think your version doesn't work, because the "afterDelay" param is relative to the moment of invocation. You would need to multiply it with "i", in the for loop, and then use 13 and 18 respectively for the last two selectors.

Look into using an NSOperationQueue. You can set its maxConcurrentOperationCount to 1, to ensure it executes its actions sequentially. E.g.

NSOperationQueue * opQueue = [[NSOperationQueue alloc] init];
opQueue.maxConcurrentOperationCount = 1; // this ensures it'll execute the actions sequentially

NSBlockOperation *spriteMethod1Invoker = [NSBlockOperation blockOperationWithBlock:^{
    for (int i = 0; i < 5; ++i)
    {
        [self spriteMethod1];
        sleep(2);  // sleep 2 secs between invoking spriteMethod1 again
    }
}];

NSInvocationOperation *spriteMethod2Invoker = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(spriteMethod2) object:nil];
[opQueue addOperation:spriteMethod1Invoker];
[opQueue addOperation:spriteMethod2Invoker];

Upvotes: 0

user2255273
user2255273

Reputation: 958

I know this might not be the best solution, but it works for me:

-(void)addObjects {
    [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:2];
    [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:4];
    [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:6];
    [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:8];
    [self performSelector:@selector(spriteMethod1) withObject:nil afterDelay:10];
    [self performSelector:@selector(spriteMethod2) withObject:nil afterDelay:13];
    [self performSelector:@selector(addObjects) withObject:nil afterDelay:18];
}

Upvotes: 1

insys
insys

Reputation: 1288

This out the top of my head.. not sure if it'll do the trick:

- (void)startAddingObjects 
{
    NSNumber *counter = @(0);
    [self performSelector:@selector(addMoreUsingCounter:) 
               withObject:counter 
               afterDelay:2];
}

- (void)addMoreUsingCounter:(NSNumber *)counter
{
    int primCounter = [counter intValue];
    if (primCounter < 5)
    {
        [self spriteMethod1];
        [self performSelector:@selector(addMoreUsingCounter:) 
                   withObject:@(primCounter++) 
                   afterDelay:2];
    }
    else if (primCounter < 7)
    {
        [self spriteMethod2];
        [self performSelector:@selector(addMoreUsingCounter:) 
                   withObject:@(primCounter++) 
                   afterDelay:3];
    }
}

You'll probably still need to relate the delay to the counter to get the exact results you need.

Upvotes: 0

Merlevede
Merlevede

Reputation: 8170

The problem is that you won't see the delay because the selector is enqueued on the thread loop. From the documentation:

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.

Another approach is to make the thread sleep for a few seconds.

[self spriteMethod1];
[NSThread sleepForTimeInterval:2.0f];

In this case your User Interface will hang if you don't execute this code in a separate thread.

Upvotes: 0

Related Questions