NSTimer в классе - PullRequest
       5

NSTimer в классе

0 голосов
/ 12 февраля 2012

У меня настроен класс таймера, который в основном обрабатывает всю логику таймера обратного отсчета.Все, что он делает, это при нажатии кнопки - отсчитывает от 60 до 0 секунд.

У меня есть следующий код в классе Timer.m.

- (void)advanceTimer
{
    self.lengthOfTime = [NSNumber numberWithInt:self.lengthOfTime.intValue - 1];
    NSLog(@"%@",self.lengthOfTime);
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer) userInfo:nil repeats:NO];
}
- (void)startCountdown
{
    if (!self.lengthOfTime) self.lengthOfTime = [NSNumber numberWithInt:60];
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer) userInfo:nil repeats:NO];
}

Что я хочу сделать, это создатьобъект таймера в моем View Controller, который будет обновлять метку из ViewController.m.В настоящее время - класс работает, потому что я могу NSLog из класса Timer, и он считает правильно.Я думал о том, чтобы вернуть метод advanceTimer, но я не могу понять, как обновить метку в ViewController с возвращенными данными.

Единственный способ получить возврат к работе -чтобы кнопка обновляла метку до правильного времени обратного отсчета ... Я не могу заставить ее автоматически отсчитывать время ...

Ответы [ 3 ]

1 голос
/ 12 февраля 2012

Класс обратного отсчета должен сохранить ссылку обратно на ViewController и затем вызвать для него метод.

Один из подходов заключается в использовании шаблона делегата.Иметь метод init класса Countdown как initWithDelegate:(id)delegate и предопределенный метод обратного вызова (например, updateCountdown:(NSNumber*)currentCountdown).ViewController отправляет себя в качестве делегата и реализует метод обновления.

Другой подход - шаблон цель / действие.NSTimer использует этот подход.Метод init будет initWithTarget:(id)target selector:(SEL)selector.ViewController отправляет себя как цель и любой селектор, который он хочет использовать (если он принимает NSNumber в качестве единственного аргумента).

В обоих случаях в advanceTimer класс обратного отсчета будет использовать performSelector:withObject:вызовите метод обновления ViewController.

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

1 голос
/ 12 февраля 2012

Ну, если вы знаете, как обновить ярлык, нажав кнопку, у вас есть все для подключения всего остального:

Если ваш контроллер представления имеет IBOutlet для метки и IBAction, который обновляет его, почему бы не вызвать действие контроллера представления в вашем методе advanceTimer?

Еще проще, вы можете подключить свой класс таймера к метке. Вы можете сделать это так:

// Timer.h:
@interface Timer : NSObject

@property (retain, nonatomic) IBOutlet UILabel *timeLabel;
@property (assign, nonatomic) NSInteger secondsRemaining;
@property (assign, nonatomic) NSTimer *timer;

- (IBAction)startCountdown:(id)sender;
- (IBAction)stopCountdown:(id)sender;
- (void)timerFired:(NSTimer *)timer;

@end

// Timer.m
@implementation Timer

@synthesize timeLabel = timeLabel_;
@synthesize secondsRemaining = secondsRemaining;
@synthesize timer = timer_;

- (void)setTimer:(NSTimer *)timer
{
    if (timer = timer_)
        return;

    [timer_ invalidate];
    timer_ = timer;
}

- (void)scheduleTimer
{
    if (self.secondsRemaining <= 0) {
        self.timer = nil;
    } else {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerFired:) userInfo:nil repeats:NO];
    }
}

- (void)timerFired:(NSTimer *)timer
{
    self.secondsRemaining -= 1;
    NSString *displayString = [NSString stringWithFormat:@"%d", self.secondsRemaining];
    self.timeLabel.text = displayString;
    [self scheduleTimer];
}

- (IBAction)startCountdown:(id)sender
{
    self.secondsRemaining = 60;
    [self scheduleTimer];
}

- (IBAction)stopCountdown:(id)sender
{
    self.timer = nil;
}

- (void)dealloc
{
    [timeLabel_ release];
    [super dealloc];
}

@end

Этот код имеет два преимущества:

  • Вы можете отменить таймер.
  • Вашему контроллеру представления не нужно ничего знать об этом - вы можете полностью настроить его в конструкторе интерфейсов.
1 голос
/ 12 февраля 2012

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

@property (nonatomic,retain) NSTimer * yourTimer;

В файле .m

@synthesize yourTimer;

А потом

- (void)advanceTimer
{
self.lengthOfTime = [NSNumber numberWithInt:self.lengthOfTime.intValue - 1];
NSLog(@"%@",self.lengthOfTime);
self.yourTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer)     userInfo:nil repeats:NO];
}
- (void)startCountdown
{
if (!self.lengthOfTime) self.lengthOfTime = [NSNumber numberWithInt:60];
self.yourTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer) userInfo:nil repeats:NO];
}

Я также исправил ваш NSNumber alloc, чтобы не было утечек памяти;) Объясняя это, NSTimer scheduleTimerWithTimeInterval: дает вам NSTimer с авто-выпуском. Если этот таймер не сохраняется каким-либо членом, он освобождается, как только метод завершается, и, поскольку никакой другой указатель не сохраняет его, он освобождается. Может быть, это объяснение;). Никогда не работал с NSTimers

...