Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone dev -- performSelector:withObject:afterDelay or NSTimer?

To repeat a method call (or message send, I guess the appropriate term is) every x seconds, is it better to use an NSTimer (NSTimer's scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:) or to have the method recursively call itself at the end (using performSelector:withObject:afterDelay)? The latter doesn't use an object, but maybe its less clear/readable? Also, just to give you an idea of what I'm doing, its just a view with a label which counts down to 12:00 midnight, and when it gets to 0, it will blink the time (00:00:00) and play a beep sound forever.

Thanks.

Edit: also, what would be the best way to repeatedly play a SystemSoundID (forever) ? Edit: I ended up using this to play the SystemSoundID forever:

// Utilities.h
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioServices.h>


static void soundCompleted(SystemSoundID soundID, void *myself);

@interface Utilities : NSObject {

}

+ (SystemSoundID)createSystemSoundIDFromFile:(NSString *)fileName ofType:(NSString *)type;
+ (void)playAndRepeatSystemSoundID:(SystemSoundID)soundID;
+ (void)stopPlayingAndDisposeSystemSoundID;

@end


// Utilities.m
#import "Utilities.h"


static BOOL play;

static void soundCompleted(SystemSoundID soundID, void *interval) {
    if(play) {
        [NSThread sleepForTimeInterval:(NSTimeInterval)interval];
        AudioServicesPlaySystemSound(soundID);
    } else {
        AudioServicesRemoveSystemSoundCompletion(soundID);
        AudioServicesDisposeSystemSoundID(soundID);
    }

}

@implementation Utilities

+ (SystemSoundID)createSystemSoundIDFromFile:(NSString *)fileName ofType:(NSString *)type {
    NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:type];
    SystemSoundID soundID;

    NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];

    AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
    return soundID;
}

+ (void)playAndRepeatSystemSoundID:(SystemSoundID)soundID interval:(NSTimeInterval)interval {
    play = YES
    AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL,
                                          soundCompleted, (void *)interval);
    AudioServicesPlaySystemSound(soundID);
}

+ (void)stopPlayingAndDisposeSystemSoundID {
    play = NO
}

@end

Seems to work fine.. And for the label blinking I'll use an NSTimer I guess.

like image 586
mk12 Avatar asked Sep 29 '09 00:09

mk12


1 Answers

A timer is more suited to a strictly defined interval. You will lose accuracy if you have your function call itself with a delay because its not really synced to a time interval. There's always the time taken to run the actual method itself as well which puts the interval out.

Stick with an NSTimer, I'd say.

like image 133
Nick Bedford Avatar answered Sep 25 '22 18:09

Nick Bedford