IPhone dev - performSelector: withObject: afterDelay или NSTimer?

Чтобы повторить вызов метода (или сообщение отправить, я думаю, соответствующий термин) каждые x секунд, лучше ли использовать NSTimer (NSTimer scheduleTimerWithTimeInterval: target: selector: userInfo: repeatats:) или иметь рекурсивный метод называть себя в конце (используя performSelector: withObject: afterDelay)? Последний не использует объект, но, возможно, его менее понятный/читаемый? Кроме того, просто для того, чтобы дать вам представление о том, что я делаю, это просто представление с меткой, которая отсчитывает до полуночи до 12:00, а когда она доходит до 0, она будет мигать (00:00:00) и воспроизводить звуковой сигнал навсегда.

Спасибо.

Edit: также, что было бы лучшим способом неоднократно воспроизводить SystemSoundID (навсегда)? Edit: Я закончил использовать это, чтобы играть SystemSoundID навсегда:

// 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

Кажется, что все нормально. И для ярлыка ярлыка я буду использовать NSTimer, я думаю.

Ответ 1

Таймер более подходит для строго определенного интервала. Вы потеряете точность, если у вас есть функция вызова с задержкой, потому что она не синхронизирована с интервалом времени. Всегда время, затрачиваемое на запуск самого самого метода, который выдает интервал.

Придерживайтесь NSTimer, я бы сказал.

Ответ 2

Чтобы добавить немного к другим ответам, случай для рекурсивного вызова будет состоять в том, что вызов может занять неизвестное время - скажем, вы повторно вызываете веб-службу с небольшим количеством данных, пока не закончите. Каждый вызов может занять некоторое неизвестное количество времени, поэтому у вас есть код, который ничего не делает до тех пор, пока веб-вызов не вернется, затем будет отправлена ​​следующая партия, пока не будет отправлено больше данных, и код снова не вызовет себя.

Ответ 3

Поскольку ваше приложение зависит от точности времени (т.е. нужно выполнять один раз в секунду), NSTimer будет лучше. Для выполнения самого метода требуется некоторое время, и NSTimer будет в порядке с этим (если ваш метод занимает менее 1 секунды, если он вызывает каждую секунду).

Чтобы повторно воспроизводить звук, вы можете установить обратный вызов завершения и воспроизвести звук там:

SystemSoundID tickingSound;

...

AudioServicesAddSystemSoundCompletion(tickingSound, NULL, NULL, completionCallback, (void*) self);

...

static void completionCallback(SystemSoundID mySSID, void* myself) {
  NSLog(@"completionCallback");

  // You can use this when/if you want to remove the completion callback
  //AudioServicesRemoveSystemSoundCompletion(mySSID);

  // myself is the object that called set the callback, because we set it up that way above
  // Cast it to whatever object that is (e.g. MyViewController, in this case)
  [(MyViewController *)myself playSound:mySSID];
}