Objective-C:完成一个间隔计时器

Posted

技术标签:

【中文标题】Objective-C:完成一个间隔计时器【英文标题】:Objective-C: Completing an interval timer 【发布时间】:2014-01-17 04:51:08 【问题描述】:

我目前正在开发一个间隔计时器,它可能会让您想到 Gymboss 计时器。比较到此结束。

假设您使用踏步机将整个锻炼时间设置为 10 分钟。您希望每次重复持续 1 分钟,每次休息 30 秒。虽然我设法在“计时”方法中编写了将在锻炼结束时播放的声音,但我仍在努力在重复或休息结束时播放声音。这是代码中标题的相关部分:

#import <AudioToolbox/AudioToolbox.h>

@interface AutoLayoutViewController : UIViewController <AVAudioPlayerDelegate>
// 1. The three green labels
// Workout's timer

    IBOutlet UILabel *workoutTimer;
    NSTimer *workoutCountdown;


// Repetition's length
@property (strong, nonatomic) IBOutlet UILabel *repetitionLabel;

// Break's length
@property (strong, nonatomic) IBOutlet UILabel *breakLabel;




// 2. The three steppers

// Stepper for Workout's total length
@property (strong, nonatomic) IBOutlet UIStepper *secondsWorkoutChanged;

// Stepper for Repetition's length
@property (strong, nonatomic) IBOutlet UIStepper *secondsRepetitionChanged;

// Stepper for Break's length
@property (strong, nonatomic) IBOutlet UIStepper *secondsBreakChanged;



// 4. The start button
@property (strong, nonatomic) IBOutlet UIButton *startPauseButton;    

@end

其次,这是实现文件的相关部分:

// 1. Steppers

// Stepper for Workout's length
- (IBAction)secondsWorkoutChanged:(UIStepper *)sender 

    /* User increases value of seconds with stepper. Whenever variable for seconds is equal or greater than 60, the program sets the value of minutes through this division: seconds / 60. */
    seconds = [sender value];
    minutes = seconds / 60;


    /* "If" statement for resetting seconds to 0 in order for the label to look like a watch. REAL number of seconds stored by stepper modulus operated by 60.
     */
    if (seconds > 59) 
        seconds = seconds % 60;
     // End if.


    [workoutTimer setText: [NSString stringWithFormat:@"%2i : %2i", (int) minutes, (int) seconds]];



// Stepper for Repetition's length
- (IBAction)secondsRepetitionChanged:(UIStepper *)sender 

    /* User increase value of secondsBreak with stepper. Whenever variable for secondsBreak exceeds 60, the program sets the value of minutesBreak by dividing the number of seconds with 60. */
    secondsRepetition = [sender value];
    minutesRepetition = secondsRepetition / 60;


    /* "If" statement for resetting secondsBreak to 0 in order for the label to look like a watch. REAL number of seconds stored by stepper modulus operated by 60.
     */
    if (secondsRepetition > 59) 

        secondsRepetition = secondsRepetition % 60;
     // End if.



    [_repetitionLabel setText: [NSString stringWithFormat:@"%2i : %2i", (int) minutesRepetition, (int) secondsRepetition]];




// Stepper for Break's length
- (IBAction)secondsBreakChanged:(UIStepper *)sender 

    /* User increase value of secondsBreak with stepper. Whenever variable for secondsBreak exceeds 60, the program sets the value of minutesBreak by dividing the number of seconds with 60. */
    secondsBreak = [sender value];
    minutesBreak = secondsBreak / 60;



    /* "If" statement for resetting secondsBreak to 0 in order for the label to look like a watch. REAL number of seconds stored by stepper modulus operated by 60.
     */
    if (secondsBreak > 59) 
        secondsBreak = secondsBreak % 60;
     // End if.



    [_breakLabel setText: [NSString stringWithFormat:@"%2i : %2i", (int) minutesBreak, (int) secondsBreak]];





// 3. The buttons

// Method for countdown

- (void)chrono:(NSTimer *)timer
 // First brace for "chrono" method.

    // Timer loses 1 second when started.
    seconds = seconds -= 1;

    workoutTimer.text = [NSString stringWithFormat: @"%2i : %2i", minutes, seconds];

    // If "statement for including minutes in countdown.
   if (seconds <= 0) 
       if (minutes <= 0) 
           [workoutCountdown invalidate]; // 1: If both minutes and seconds = 0, countdown ends.


           // 1.1: Alarm for end of workout.
           CFBundleRef workoutEnded = CFBundleGetMainBundle();
           CFURLRef soundFileURLRef;
           soundFileURLRef = CFBundleCopyResourceURL(workoutEnded, (CFStringRef) @"alarm_clock_ringing", CFSTR ("wav"), NULL);

           UInt32 soundID;
           AudioservicesCreateSystemSoundID(soundFileURLRef, &soundID);
           AudioServicesPlaySystemSound(soundID);


           // Reset all steppers when workout ends.
           _secondsWorkoutChanged.value = 0;

           _secondsRepetitionChanged.value = 0;

           _secondsBreakChanged.value = 0;


           // Reset the text displayed in the label to zero.
           [workoutTimer setText:@"00 : 00"];

           [_repetitionLabel setText:@"00 : 00"];

           [_breakLabel setText:@"00 : 00"];


        // End of "if" statement" for minutes.

       else  // Timer still running
           seconds = 60;
           minutes -= 1;

        // End of else.

     // End of all the "if" (general).


 // Last brace for "chrono" method.



 //Start button
-(IBAction) startPauseButton:(UIButton *)sender 
    workoutCountdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(chrono:) userInfo:nil repeats:YES];

我的问题如下。当重复和中断结束时,如何播放声音?出于演示的目的,您可以使用来自“chrono”方法的声音的代码行。

谢谢。

安科

【问题讨论】:

嗨。你能澄清一下 repititionbreak 的术语吗?所有的计时器都应该同时开始吗?如果可能,请通过示例提供计时器的工作流程。 假设用户正在做仰卧起坐。他的整个锻炼时间为10分钟。在他按下“开始”按钮一分钟后,他会听到第一个警报(重复),告诉他/她停止他的仰卧起坐。在第一个警报后 30 秒,他/她将听到另一个警报告诉他/她休息结束。之后,两个警报将在一个循环中相互跟随,直到锻炼结束。我确信我必须在“chrono”方法中设置一个循环才能发生这种情况。 这是我目前所了解的。重复警报确定您在一次连续拉伸或一组中锻炼多长时间。休息警报设置休息时间。当重复计时器达到零倒计时时,总锻炼计时器暂停。此时,重复警报被重置为其原始值并且中断计时器启动。当休息计时器达到零时,锻炼计时器和重复计时器开始其下一个循环。到目前为止我是对的吗? 在锻炼期间,除非用户按下“暂停”按钮,否则“总锻炼计时器”将继续运行。至于其他两个组件,当重复计时器达到零时,警报将重置为其原始值,并且休息计时器启动。当中断计时器达到零时,重复计时器和中断计时器进入下一个循环。到目前为止,这就是我项目的全貌。 【参考方案1】:

尝试在您的实施文件中实施以下更改: [ 注意:我重新定位了变量的声明语句,并添加了两个新的变量secondsValueminutesValue]

@implementation CDTViewController // instance variables int seconds; int minutes; int secondsRepetition; int minutesRepetition; int secondsBreak; int minutesBreak; int secondsValue; int minutesValue; BOOL startBreakTimer; BOOL startRepetitionTimer; - (void)viewDidLoad [super viewDidLoad]; startRepetitionTimer = YES; startBreakTimer = NO;
- (IBAction)secondsRepetitionChanged:(UIStepper *)sender 

    minutesRepetition = [sender value] / 60;
    secondsRepetition = (int)[sender value] % 60;
    secondsValue = secondsRepetition;
    minutesValue = minutesRepetition;
    [_repetitionLabel setText: [NSString stringWithFormat:@"%2i : %2i", (int) minutesRepetition, (int) secondsRepetition]];
- (IBAction)secondsBreakChanged:(UIStepper *)sender 

    minutesBreak = [sender value] / 60;
    secondsBreak = (int)[sender value] % 60;
    [_breakLabel setText: [NSString stringWithFormat:@"%2i : %2i", (int) minutesBreak, (int) secondsBreak]];
- (void)chrono:(NSTimer *)timer

    seconds -= 1;
    secondsValue -= 1;

    if (seconds < 0) 
        seconds = 59;
        minutes -= 1;
        if (minutes < 0) 
            minutes = 0;
        
    

    if (secondsValue < 0) 
        secondsValue = 59;
        minutesValue -= 1;
        if (minutesValue < 0) 
            minutesValue = 0;
        
    

    workoutTimer.text = [NSString stringWithFormat: @"%2i : %2i", minutes, seconds];

    if (startRepetitionTimer) 
        _repetitionLabel.text = [NSString stringWithFormat: @"%2i : %2i",minutesValue, secondsValue];
        _breakLabel.text = [NSString stringWithFormat: @"%2i : %2i", minutesBreak, secondsBreak];
        if (secondsValue == 0) 
            if (minutesValue == 0) 
                startBreakTimer = YES;
                startRepetitionTimer = NO;
                secondsValue = secondsBreak;
                minutesValue = minutesBreak;

                /* write code to play repetition alarm
             here */
            
        
    
    else if (startBreakTimer) 
        _repetitionLabel.text = [NSString stringWithFormat: @"%2i : %2i",minutesRepetition, secondsRepetition];
        _breakLabel.text = [NSString stringWithFormat: @"%2i : %2i", minutesValue, secondsValue];
        if (secondsValue == 0) 
            if (minutesValue == 0) 
                startBreakTimer = NO;
                startRepetitionTimer = YES;
                secondsValue = secondsRepetition;
                minutesValue = minutesRepetition;

                /* write code to play break alarm
             here */
            
        
    

    if (seconds == 0) 
        if (minutes == 0) 
            [workoutCountdown invalidate];

            // Alarm for end of workout.

            // Reset all steppers when workout ends.
            _secondsWorkoutChanged.value = 0;
            _secondsRepetitionChanged.value = 0;
            _secondsBreakChanged.value = 0;

            // Reset the text displayed in the label to zero.
            [workoutTimer setText:@"00 : 00"];
            [_repetitionLabel setText:@"00 : 00"];
            [_breakLabel setText:@"00 : 00"];
            return;
        
    

希望这个逻辑对你有帮助!

【讨论】:

再次感谢您的回答!我测试了你在 iOS 模拟器中描述的逻辑,它可以工作。

以上是关于Objective-C:完成一个间隔计时器的主要内容,如果未能解决你的问题,请参考以下文章

秒表的使用方法 秒表有几种计时方式

定时器、SetInterval、报警等

如何在固定时间间隔后重复执行异步任务

CC2530强化实训03定时器间隔定时实现按键N连击

多个计时器已过问题

简单的jQuery定时器