AVAudioSequencer 在 Deinit/Segue 上导致崩溃:'required condition is false: outputNode'

AVAudioSequencer Causes Crash on Deinit/Segue: 'required condition is false: outputNode'

每当对象被取消初始化时(例如,当执行展开转场回到另一个 ViewController 时),以下代码会导致崩溃并出现以下错误:

required condition is false: [AVAudioEngineGraph.mm:4474:GetDefaultMusicDevice: (outputNode)]

Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: outputNode'

AVAudioSequencer 是问题的根源,因为如果删除它,错误就会停止。

如何避免这种崩溃?

class TestAudioClass {
    
    private var audioEngine: AVAudioEngine
    private var sampler: AVAudioUnitSampler
    private var sequencer: AVAudioSequencer
    
    init() {
        self.audioEngine = AVAudioEngine()
        self.sampler = AVAudioUnitSampler()
        audioEngine.attach(sampler)
        audioEngine.connect(sampler, to: audioEngine.mainMixerNode, format: nil)
        self.sequencer = AVAudioSequencer(audioEngine: audioEngine)
        if let fileURL = Bundle.main.url(forResource: "TestMusic", withExtension: "mid") {
            do {
                try sequencer.load(from: fileURL, options: AVMusicSequenceLoadOptions())
            } catch {
                print("Error loading sequencer: \(error.localizedDescription)")
            }
        }
        sequencer.prepareToPlay()
    }
}

此崩溃可能会令人困惑,并且如果尚未加载音序器的内容,也可能不会向控制台输出任何错误消息。非常无用!

AVAudioSequencer 确实是问题的原因。要修复它,请使音序器成为隐式展开的可选(即添加 ! 到其类型)并添加显式指令以在 deinit 之前 期间停止和删除它对象的其余部分被取消初始化。

固定代码如下(特别注意deinit方法):

class TestAudioClass {

    private var audioEngine: AVAudioEngine
    private var sampler: AVAudioUnitSampler
    private var sequencer: AVAudioSequencer!

    init() {
        self.audioEngine = AVAudioEngine()
        self.sampler = AVAudioUnitSampler()
        audioEngine.attach(sampler)
        audioEngine.connect(sampler, to: audioEngine.mainMixerNode, format: nil)
        self.sequencer = AVAudioSequencer(audioEngine: audioEngine)
        if let fileURL = Bundle.main.url(forResource: "TestMusic", withExtension: "mid") {
            do {
                try sequencer.load(from: fileURL, options: AVMusicSequenceLoadOptions())
            } catch {
                print("Error loading sequencer: \(error.localizedDescription)")
            }
        }
        sequencer.prepareToPlay()
    }

    deinit {
        sequencer.stop()
        sequencer = nil
    }
}

希望对您有所帮助!