Question

I want to be able to execute a delay every time that a function loops through a loop. I already have a loop setup, as shown below:

for (float batteryPercentage = 1; batteryPercentage <= 0; batteryPercentage -= 0.01)
    {
        double timeUntilNextDegreeDrop = 9.0;
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeUntilNextDegreeDrop * NSEC_PER_SEC));
        dispatch_after (time, dispatch_get_main_queue(), ^(void)
        {
            [batteryLevel setProgress:batteryPercentage animated:YES];

            float batteryLevelPercentage = batteryPercentage * 100;
            batteryLevelLabel.text = [NSString stringWithFormat:@"Battery Level: %f%%", batteryLevelPercentage];
        });
    }

batteryPercentage is the variable that I am trying to decrement from 1 to 0 by 0.01 every 9 seconds until the value reaches 0. The total length of the program should be 900 seconds (15 minutes). Every 9 seconds, I want this code to execute every nine seconds and to change the value of the UIProgressView called batteryLevel. Then, I want to multiply batteryPercentage by 100, to get a whole percentage number, such as multiplying 0.67 to get 67, then replace the batteryLevelLabel text with the new value. When I try and execute this, the batteryLevel Progress View simply doesn't fill and the text doesn't change. I'm assuming there's something wrong with the timer, so what would be a more effective way of inputing a 9 second delay?

Was it helpful?

Solution

try with nstimer as suggested

[NSTimer scheduledTimerWithTimeInterval:9.0
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:YES];

//targetMethod will be called every 9 second //call [myTimer invalidate]; myTimer = nil; when your task is done

OTHER TIPS

Here's a way to do it that keeps close to your existing structure using NSThread:

@interface MyThread : NSThread
@end

@implementation MyThread

-(void)main
{
    NSDate * when = [ NSDate date ] ;

    for ( int battery = 1000; battery >= 0; battery -= 1 )
    {
        when = [ NSDate dateWithTimeInterval:1.0 sinceDate:when ] ;
        [ NSThread sleepUntilDate:when ] ;

        [ [ NSThread mainThread ] perform:^{
            [batteryLevel setProgress:(CGFloat)battery / 10.0 animated:YES];
            batteryLevelLabel.text = [NSString stringWithFormat:@"Battery Level: %f%%", (CGFloat)battery / 10.0 ];
        }];
    }
}

@end

helper category:

@implementation NSThread (Perform)

-(void)_perform:(void(^)())block
{
    block() ;
}

-(void)perform:(void(^)())block
{
    BOOL wait = [ NSThread currentThread ] == self ;
    [ self performSelector:@selector( _perform: ) onThread:self withObject:[ block copy ] waitUntilDone:wait ] ;
}

@end

Then start your timer with NSThread * thread = [ [ MyThread alloc ] init ] ; [ thread start ] ;

Probably easier to just rework your app to use a standard NSTimer + callback structure...

(I also did one using GCD to see what it looks like:

dispatch_queue_t q = dispatch_queue_create( NULL, NULL ) ;
dispatch_async( q, ^{
    NSDate * when = [ NSDate date ] ;

    for ( int battery = 1000; battery >= 0; battery -= 1 )
    {
        dispatch_sync( dispatch_get_main_queue(), ^{
            [batteryLevel setProgress:(CGFloat)battery / 10.0 animated:YES];
            batteryLevelLabel.text = [NSString stringWithFormat:@"Battery Level: %f%%", (CGFloat)battery / 10.0 ];
        }) ;

        when = [ NSDate dateWithTimeInterval:1.0 sinceDate:when ] ;
        [ NSThread sleepUntilDate:when ] ;
    }
}) ;

(But I don't think it's guaranteed that different queues are on different threads)

You can use + (void)sleepUntilDate:(NSDate *)aDate !

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top