You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击Next按钮时AVAudioPlayer无法触发音频播放的问题求助

音频播放失败问题排查

问题场景

点击「Next」按钮后,文本光标移动至带有星号「*」的单词时,音频应自动播放,但实际无法正常工作。

相关代码

View代码

import AVFoundation
import SwiftUI

struct SutraView: View {
    private var audioPlayer: AVAudioPlayer?
    private mutating  func playAVAudio(text: String) {
        
        guard let audioFilePath = Bundle.main.path(forResource: "Mokugyo", ofType: "mp3") else {
            return
        }
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioFilePath))
            audioPlayer?.prepareToPlay()
        } catch {
            print("Error")
        }
    }
}

ViewModel代码

import SwiftUI
import AVFoundation

class SutraViewModel: ObservableObject {
    
    // MARK: - Properties
    private let sutraText: String // text form Model
    private var audioPlayer: AVAudioPlayer?
    
    @Published var itemsToShow: AttributedString? // what  will show
    @Published var currentIndex: Int = 0
    
    // MARK: - Initialization for SutraModel
    init(model: SutraModel) {
        self.sutraText = model.sutraText
    
    }
    
    // MARK: - Public methods
    func buttonDidPressed() {
        currentIndex += 1
        highlightCurrentWord(text: sutraText)
    }
    
    // MARK: Private methods
    private func highlightCurrentWord(text: String) {
        let attributedString = NSMutableAttributedString(string: sutraText) // string can containe design
        let itemsArray = sutraText.createArrayOfWords()
        
        if currentIndex < itemsArray.count {
            let wordsWithSpaces = sutraText.split(separator: " ")
            var characterCount = 0
            for index in 0..<currentIndex {
                characterCount += wordsWithSpaces[index].count + 1
            }
            let range = NSRange(location: characterCount, length: itemsArray[currentIndex].count)
            //attributedString.addAttribute(.backgroundColor, value: UIColor.green, range: range)
            attributedString.addAttribute(.foregroundColor, value: UIColor.black, range: range)
            
            let currentWord = itemsArray[currentIndex]
            if currentWord.contains("*") {
                audioPlayer?.play()
            }
        }
        self.itemsToShow = AttributedString(attributedString)
    }
}

问题分析

核心问题是ViewModel里的audioPlayer从未被初始化,一直处于nil状态。当代码执行到audioPlayer?.play()时,可选链调用会直接跳过nil对象的方法执行,自然不会播放音频。另外View中的playAVAudio方法从未被调用,属于冗余代码,对当前逻辑没有帮助。

解决方案

  1. 在ViewModel初始化阶段完成音频播放器的实例化,确保audioPlayer有有效对象。
  2. 完善错误处理逻辑,打印具体错误信息,方便排查音频文件是否存在、路径是否正确。
  3. 删除View中未使用的音频相关代码,保持代码整洁。

修改后的代码

View代码(简化后)

import AVFoundation
import SwiftUI

struct SutraView: View {
    // 移除未使用的audioPlayer和playAVAudio方法
    var body: some View {
        // 你的视图内容
    }
}

ViewModel代码(修复后)

import SwiftUI
import AVFoundation

class SutraViewModel: ObservableObject {
    
    // MARK: - Properties
    private let sutraText: String
    private var audioPlayer: AVAudioPlayer?
    
    @Published var itemsToShow: AttributedString?
    @Published var currentIndex: Int = 0
    
    // MARK: - Initialization
    init(model: SutraModel) {
        self.sutraText = model.sutraText
        // 初始化音频播放器
        setupAudioPlayer()
    }
    
    // MARK: - Public methods
    func buttonDidPressed() {
        currentIndex += 1
        highlightCurrentWord(text: sutraText)
    }
    
    // MARK: Private methods
    private func setupAudioPlayer() {
        guard let audioFilePath = Bundle.main.path(forResource: "Mokugyo", ofType: "mp3") else {
            print("错误:找不到Mokugyo.mp3文件,请检查文件名和路径")
            return
        }
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioFilePath))
            audioPlayer?.prepareToPlay()
            print("音频播放器初始化成功")
        } catch {
            print("音频初始化失败:\(error.localizedDescription)")
        }
    }
    
    private func highlightCurrentWord(text: String) {
        let attributedString = NSMutableAttributedString(string: sutraText)
        let itemsArray = sutraText.createArrayOfWords()
        
        guard currentIndex < itemsArray.count else { return }
        
        let wordsWithSpaces = sutraText.split(separator: " ")
        var characterCount = 0
        for index in 0..<currentIndex {
            characterCount += wordsWithSpaces[index].count + 1
        }
        let range = NSRange(location: characterCount, length: itemsArray[currentIndex].count)
        attributedString.addAttribute(.foregroundColor, value: UIColor.black, range: range)
        
        let currentWord = itemsArray[currentIndex]
        if currentWord.contains("*") {
            // 此时audioPlayer已初始化,调用play会正常执行
            audioPlayer?.play()
        }
        
        self.itemsToShow = AttributedString(attributedString)
    }
}

额外提示

  • 确保Mokugyo.mp3已正确添加到项目中,且在Target的Build Phases -> Copy Bundle Resources列表里能找到该文件。
  • 如果需要重复播放音频,可以在调用play()前再次调用prepareToPlay(),避免音频播放完毕后无法触发再次播放的问题。

内容的提问来源于stack exchange,提问作者Kuralay Biehler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:49:56