read() to AVMIDIPlayer problem

I'm trying to write an app that will load MIDI files. I've written a Swfit script that works perfectly, but I'm having trouble with putting that into an app.


override func read(from data: Data, ofType typeName: String) throws {

let theMIDIPlayer = try AVMIDIPlayer.init(data: data, soundBankURL: nil)

throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)

}


I'm getting a yellow warning that theMIDIPlayer was never initialized. Xcode made me put in the 'try': is that the reason? As a result, I can't use this in the ViewController, as it claims there's no such member of Document.


override func viewDidAppear() {

let document = self.view.window?.windowController?.document as! Document

self.theView = document.theMIDIPlayer

}


Thanks.

Replies

If you use try, you need to use a

do { 
     try
} catch {
}

pattern


Or use a try?

if let try? {
     do something 
} else {
     throw
}



Read details here

h ttps://cocoacasts.com/what-is-the-difference-between-try-try-and-try

No, none of that worked. It just flagged up loads more errors.


At best, this produces exactly the same warning, that the Initialization of theMIDIPlayer was never used.

do {

let theMIDIPlayer = try AVMIDIPlayer.init(data: data, soundBankURL: nil)

}catch {

throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)

}

I've tried doing read from URL, too!

In fact, just trying to assign a variable doesn't work. Presumably it's complaining that the variable is never used because the code never gets to the third line. Which means that any code won't work?????


override func read(from data: Data, ofType typeName: String) throws {

do {

let thisOneThing = try "String"

This could help:

h ttps://www.rockhoppertech.com/blog/swift-and-avmidiplayer/

or

ttps://gist.github.com/genedelisa/522edb2c656b1ce4fe42


soundBank must be defined, not be nil if this is an IOS App

Important

For macOS the

bankURL
can be set to nil to use the default sound bank. However, iOS must always refer to a valid bank file.

No, soundbank can be Nil on MacOS, and it will use the default MIDI library. Thanks for investigating. (Also, that doesn't explain why a simple variable assignment doesn't work either.)


However, it seems to be working now, and I have no idea what has changed.

So, this is a MacOS App (you never told).


In that case, effectively, as I said "For macOS the

bankURL
can be set to nil"


I have no idea either what as changed, as you just show very small code fragments 😉


Anyway, thanks for feedback and don't forget to close the thread.

You should better clarify some things...

- On whiich platform does your app run? -- macOS

- Are creating a Document-based app?

- In what classes do the shown method exist?

...

All such things may affect. You should better show whole code of your classes.


And some points...

- If you want to use the instantiated AVMIDIPlayer later, you need to keep it somewhere other than the local variable.

- AVMIDIPlayer cannot be a `view`, so `self.theView = document.theMIDIPlayer` does not make sense.


class Document: NSDocument {
    //...

    var theMIDIPlayer: AVMIDIPlayer? // Declare `theMIDIPlayer` as an instance member of Document
    
    override func read(from data: Data, ofType typeName: String) throws {
        theMIDIPlayer = try AVMIDIPlayer(data: data, soundBankURL: nil) // Do not declare `let`-constant here
    }
    
}


class ViewController: NSViewController {
    //...

    override func viewDidAppear() {
        let document = self.view.window?.windowController?.document as! Document
        if let midiPlayer = document.theMIDIPlayer {
            //Use `midiPlayer`
            //...
        }
    }

}


But I'm not sure keeping an AVMIDIPlayer as a property of Document is a good thing or not, you may need to re-consider your app's overall structure.

Thanks for the reply. Yes, it's a MacOS document-based app.


The read function is a method of the Document class. Each document is a MIDI file. Surely, the read function needs to initialize AVMIDIPlayer for each document? How would you do it otherwise?


I have this now, which is working. This is all the code I've written in Document.swift. The rest is boilerplate.

class Document: NSDocument {
   
    var theMIDIPlayer: AVMIDIPlayer?

    override func read(from data: Data, ofType typeName: String) throws {
        self.theMIDIPlayer = try AVMIDIPlayer.init(data: data, soundBankURL: nil)
        if self.theMIDIPlayer == nil {
             throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
         }
    }