0

I'm using AVMIDIPlayer in macOS. The .play function takes a completion handler, AVMIDIPlayerCompletionHandler, which is a typealias for Void.

My code is:

   var viewMIDIPlayer: AVMIDIPlayer?

 @IBAction func backToStart(_ sender: Any) {
        if viewMIDIPlayer != nil {
        viewMIDIPlayer!.stop()
        viewMIDIPlayer!.currentPosition = TimeInterval(0)
        playButton.state=NSControl.StateValue(rawValue: 1)
        viewMIDIPlayer!.prepareToPlay()
        viewMIDIPlayer!.play(self.completed())
            }
        }
        
        func completed() -> AVMIDIPlayerCompletionHandler {
             if self.viewMIDIPlayer!.currentPosition == self.viewMIDIPlayer!.duration {
                 self.playButton.state=NSControl.StateValue(rawValue: 0)
                 return
             }
}

What I get is an error that the function in .play is unused, and an error in the function itself "Non-void function should return a value".

enter image description here

If I try return Void or return nil, or return 0, I get type errors. Also this:

enter image description here

I've also tried something like:

viewMIDIPlayer!.play(self.completed?: (AVMIDIPlayerCompletionHandler) -> ())

but that just makes matters worse.

I dare say this is something super obvious like more punctuation, but I've got no idea. Thanks.

benwiggy
  • 1,440
  • 17
  • 35
  • What happens if you remove `-> AVMIDIPlayerCompletionHandler` from the function signature so it is just `func completed() { ... }` – Andrew Jul 05 '22 at 10:32
  • Cannot convert value of type '()' to expected argument type 'AVMIDIPlayerCompletionHandler?' (aka 'Optional<() -> ()>') – benwiggy Jul 05 '22 at 10:34
  • I think you need to include more in your question. Please update it so that it is is a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). As it currently stands it is very hard to debug with out reproducible example. Also `AVMIDIPlayerCompletionHandler` is not a typealias for `Void` it is a typealias for a function that returns `Void`. That is what `() -> Void` means – Andrew Jul 05 '22 at 10:38
  • @Andrew Don't worry, someone's figured out and explained the function type issue. Still don't know why Xcode complains that a function which returns void is 'unused', though. – benwiggy Jul 05 '22 at 11:41
  • Try removing the `()` from the end of `self.completed()` – Andrew Jul 05 '22 at 11:41
  • No, I get the same error as my first comment, in addition to the existing one. – benwiggy Jul 05 '22 at 11:43
  • Ah: it was just a 'lingering' error that went away when I tried building! Fixed! Thank you for your help. – benwiggy Jul 05 '22 at 11:45

1 Answers1

1

So the completion handler type alias is for a value of type () -> Void That means you have to pass it a function that takes no arguments and returns no value.

It's basically saying you give me a function and I'll call you back when I am done.

Now let's look at your types:

viewMIDIPlayer!.play(self.completed())

What is the type of the expression "self.completed()"

func completed() -> AVMIDIPlayerCompletionHandler {

Which is another way of saying

func completed() -> () -> Void { 

i.e. completed is a function that when you call it will return a function that takes no arguments and returns a void.

A better name for such a function would be "makeCompletionHandler"

And you might write it like:

func makeCompletionHandler() -> () -> Void {
    // I am not returning void, I am returning a function (note the braces here):
    return {
        print("Completion handler was called!")
    }
}

But there's absolutely no reason to have this kind of higher-order function. And you didn't write it like that, you wrote a function that returns void as if it was the completion handler, and not a function that returns a completion handler.

You could just write the completion handler inline, like:

viewMIDIPlayer!.play {
     if self.viewMIDIPlayer!.currentPosition == self.viewMIDIPlayer!.duration {
         self.playButton.state=NSControl.StateValue(rawValue: 0)
}
Shadowrun
  • 3,572
  • 1
  • 15
  • 13