metronome sample code with swift

Hi friend,

In apple sample code: Metronome, it uses ViewController.m to init metronome swift class as in follow link:

https://developer.apple.com/library/content/samplecode/HelloMetronome/Listings/iOSHelloMetronome_ViewController_m.html#//apple_ref/doc/uid/TP40017587-iOSHelloMetronome_ViewController_m-DontLinkElementID_14


And now I want to use swift ViewController.swift to replace all Objective C part within the sample code.


But I tried first to rewrite following code line with Swift but failed:


metronome = [[Metronome alloc] init];


the whole original Objective C sample code part as follows, please help, thanks!

------------------------------------------


#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIButton *button;
@property (weak, nonatomic) IBOutlet UITextField *barTextField;
@property (weak, nonatomic) IBOutlet UITextField *beatTextField;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.

  NSLog(@"Hello, Metronome!\n");

  NSError *error = nil;
  AVAudioSession *audioSession = [AVAudioSession sharedInstance];

  [audioSession setCategory:AVAudioSessionCategoryAmbient error:&error];
  if (error) {
  NSLog(@"AVAudioSession error %ld, %@", error.code, error.localizedDescription);
  }

  [audioSession setActive:YES error:&error];
  if (error) {
  NSLog(@"AVAudioSession error %ld, %@", error.code, error.localizedDescription);
  }

  // if media services are reset, we need to rebuild our audio chain
  [[NSNotificationCenter defaultCenter] addObserver:self
  selector:@selector(handleMediaServicesWereReset:)
  name:AVAudioSessionMediaServicesWereResetNotification
  object:audioSession];

  metronome = [[Metronome alloc] init];
  metronome.delegate = self;
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
  // Dispose of any resources that can be recreated.
}

#pragma mark- Actions
- (IBAction)buttonPressed:(UIButton*)sender {
  // change the selected state thereby the button color and title
  // toggle between Start & Stop
  sender.selected = !sender.selected;

  if (metronome.isPlaying) {
  [metronome stop];
  } else {
  [metronome start];
  }
}

#pragma mark- Delegate
- (void)metronomeTicking:(Metronome * _Nonnull)metronome bar:(int32_t)bar beat:(int32_t)beat {

  dispatch_async(dispatch_get_main_queue(), ^{
  self.barTextField.text = [NSString stringWithFormat:@"%d", bar];
  self.beatTextField.text = [NSString stringWithFormat:@"%d", beat];
  });
}

#pragma mark- AVAudioSession Notifications
// see https://developer.apple.com/library/content/qa/qa1749/_index.html
- (void)handleMediaServicesWereReset:(NSNotification *)notification
{
  NSLog(@"Media services have reset...");

  // tear down
  metronome.delegate = nil;
  metronome = nil;

  self.button.selected = NO;

  // re-create
  metronome = [[Metronome alloc] init];
  metronome.delegate = self;

  NSError *error = nil;
  [[AVAudioSession sharedInstance] setActive:YES error:&error];
  if (error) {
  NSLog(@"AVAudioSession error %ld, %@", error.code, error.localizedDescription);
  }
}

@end
Answered by QuinceyMorris in 296403022

OK, I translated it for you. This code compiles, but I haven't tested it. This is for a file "ViewController.swift", and you can delete both "ViewController.m" and "ViewController.h". Don't forget to re-connect the 3 outlets to the storyboard and hook up the button action! (Also, just to be safe, reselect the ViewController class for the view controller in the storyboard, using the Identity inspector.)


No guarantees that this is error-free!


import UIKit
import AVFoundation


class ViewController: UIViewController, MetronomeDelegate
{
    @IBOutlet weak var button: UIButton?
    @IBOutlet weak var barTextField: UITextField?
    @IBOutlet weak var beatTextField: UITextField?
   
    var metronome: Metronome!
   
    override func viewDidLoad () {
        super.viewDidLoad ()
       
        print ("Hello, Metronome!\n");
       
        let audioSession = AVAudioSession.sharedInstance ()
       
        do {
            try audioSession.setCategory (AVAudioSessionCategoryAmbient)
            try audioSession.setActive (true)
        }
        catch {
            print (error)
        }
       
        // if media services are reset, we need to rebuild our audio chain
       
        NotificationCenter.default.addObserver (self,
                                                selector: #selector (handleMediaServicesWereReset(_:)),
                                                name: NSNotification.Name.AVAudioSessionMediaServicesWereReset,
                                                object: audioSession)
       
        metronome = Metronome ()
        metronome.delegate = self
    }
   
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
   
    @IBAction func buttonPressed (sender: UIButton!) {
        // change the selected state thereby the button color and title
        // toggle between Start & Stop
        sender.isSelected = !sender.isSelected
       
        if metronome.isPlaying {
            metronome.stop ()
        }
        else {
            metronome.start ()
        }
    }
   
    @objc func metronomeTicking (_ metronome: Metronome, bar: Int32, beat: Int32) {
        DispatchQueue.main.async {
            self.barTextField!.text = String (format: "%d", bar)
            self.beatTextField!.text = String (format: "%d", beat)
        }
    }
   
    // see https://developer.apple.com/library/content/qa/qa1749/_index.html
   
    @objc func handleMediaServicesWereReset (_ notification: Notification) {
        print("Media services have reset...")
       
        // tear down
        metronome.delegate = nil
        metronome = nil
       
        button!.isSelected = false
       
        // re-create
        metronome = Metronome ()
        metronome.delegate = self
       
        do {
            try AVAudioSession.sharedInstance ().setActive (true)
        }
        catch {
            print (error)
        }
    }
}

any help? thanks

Please, tell where it fails.


And please, format the code with the formatter tool (<>)

Unfortunately, you're going to need a bit of Obj-C knowledge to convert the code, but probably not much. 🙂


This:


metronome = [[Metronome alloc] init];


is the Obj-C way of creating a new Metronome instance with an initializer having no parameters. The Swift equivalent is::


metronome = Metronome ()

thanks QuinceyMorris for your prompt reply 🙂

I used your code: metronome = Metronome ()

but got following error:

'Use of Unresolved Identifier' metronome


please help, thanks

Accepted Answer

OK, I translated it for you. This code compiles, but I haven't tested it. This is for a file "ViewController.swift", and you can delete both "ViewController.m" and "ViewController.h". Don't forget to re-connect the 3 outlets to the storyboard and hook up the button action! (Also, just to be safe, reselect the ViewController class for the view controller in the storyboard, using the Identity inspector.)


No guarantees that this is error-free!


import UIKit
import AVFoundation


class ViewController: UIViewController, MetronomeDelegate
{
    @IBOutlet weak var button: UIButton?
    @IBOutlet weak var barTextField: UITextField?
    @IBOutlet weak var beatTextField: UITextField?
   
    var metronome: Metronome!
   
    override func viewDidLoad () {
        super.viewDidLoad ()
       
        print ("Hello, Metronome!\n");
       
        let audioSession = AVAudioSession.sharedInstance ()
       
        do {
            try audioSession.setCategory (AVAudioSessionCategoryAmbient)
            try audioSession.setActive (true)
        }
        catch {
            print (error)
        }
       
        // if media services are reset, we need to rebuild our audio chain
       
        NotificationCenter.default.addObserver (self,
                                                selector: #selector (handleMediaServicesWereReset(_:)),
                                                name: NSNotification.Name.AVAudioSessionMediaServicesWereReset,
                                                object: audioSession)
       
        metronome = Metronome ()
        metronome.delegate = self
    }
   
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
   
    @IBAction func buttonPressed (sender: UIButton!) {
        // change the selected state thereby the button color and title
        // toggle between Start & Stop
        sender.isSelected = !sender.isSelected
       
        if metronome.isPlaying {
            metronome.stop ()
        }
        else {
            metronome.start ()
        }
    }
   
    @objc func metronomeTicking (_ metronome: Metronome, bar: Int32, beat: Int32) {
        DispatchQueue.main.async {
            self.barTextField!.text = String (format: "%d", bar)
            self.beatTextField!.text = String (format: "%d", beat)
        }
    }
   
    // see https://developer.apple.com/library/content/qa/qa1749/_index.html
   
    @objc func handleMediaServicesWereReset (_ notification: Notification) {
        print("Media services have reset...")
       
        // tear down
        metronome.delegate = nil
        metronome = nil
       
        button!.isSelected = false
       
        // re-create
        metronome = Metronome ()
        metronome.delegate = self
       
        do {
            try AVAudioSession.sharedInstance ().setActive (true)
        }
        catch {
            print (error)
        }
    }
}

Thanks QuinceyMorrisso so much!!! It's really error-free!

Sorry just reply because I was afraid to have further questions and want to get your help in the future🙂 😁

metronome sample code with swift
 
 
Q