如何管理每个tableviewCell中的AVAudioPlayer isPlaying?

How to manage the AVAudioPlayer isPlaying in each tableviewCell?

我有一个表视图,并且在表视图中有多个单元格。
每个单元格都有一个 AVAudioPlayer
项 我遇到了一个问题。
我不知道如何管理AVAudioPlayer。
当我先播放AVAudioPlayer,再播放第二个AVAudioPlayer时,声音会重叠
如何在我的自定义单元格中停止第一个 AVAudioPlayer,并播放第二个 AVAudioPlayer?
谢谢。

这是我自定义的单元格:

class TableViewCell: UITableViewCell {

@IBOutlet weak var myImageView: UIImageView!
@IBOutlet weak var myChatBubbleView: UIView!
@IBOutlet weak var myDateLabel: UILabel!
@IBOutlet weak var mySecondLabel: UILabel!
@IBOutlet weak var myRecordPlayerBtn: MenuButton!
private var timer:Timer?   
private var elapsedTimeInSecond:Int = 0
var audioPlayer:AVAudioPlayer?
var message:ChatroomMessage?
var chatroomId:String = ""
var delegate:PlayRecordDelegate?

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code

    self.backgroundColor = defaultBackgroundColor
    self.tintColor = defaultChatroomCheckButtonColor

    myImageView.layer.masksToBounds = true 
    myImageView.layer.cornerRadius = defaultIconRadius

    myChatBubbleView.backgroundColor = defaultChatGreenBubbleColor
    myChatBubbleView.layer.cornerRadius = defaultButtonRadius

    myDateLabel.textColor = defaultChatTimeColor

    mySecondLabel.textColor = defaultChatTimeColor
    mySecondLabel.isHidden = true

    myRecordPlayerBtn.imageView?.animationDuration = 1
    myRecordPlayerBtn.imageView?.animationImages =  [
    UIImage(named: "img_myRocordPlaying1")!,
    UIImage(named: "img_myRocordPlaying2")!,
    UIImage(named: "img_myRocordPlaying3")!
    ]
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}

func loadByMessage(_ message:ChatroomMessage, chatroomId:String) {
    self.message = message
    self.chatroomId = chatroomId

    myRecordPlayerBtn.addTarget(self, action: #selector(recordPlay), for: .touchUpInside)
}

func resetRecordAnimation() {
    self.myRecordPlayerBtn.imageView!.stopAnimating()
    self.myRecordPlayerBtn.isSelected = false
}

func recordPlay(_ sender: UIButton) {

    self.myRecordPlayerBtn.imageView?.startAnimating()

    let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(chatroomId)/Record/")

    let fileName = message?.content.substring(from: 62)
    let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)
    if FileManager.default.fileExists(atPath: fileURL.path) {

        let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
        let audioDuration = asset.duration
        let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
        self.elapsedTimeInSecond = Int(audioDurationSeconds)

        if audioPlayer?.isPlaying == true {

            audioPlayer?.stop()

            DispatchQueue.main.async {
                self.resetTimer(second: self.elapsedTimeInSecond)
                self.startTimer()
            }

        }

        updateTimeLabel()
        startTimer()

        audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
        audioPlayer?.delegate = self
        audioPlayer?.play()

    }else{
        //don't have file in local
        let recordUrl = URL(string: (message?.content)!)
        URLSession.shared.downloadTask(with: recordUrl!, completionHandler: { (location, response, error) in

            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
                let location = location, error == nil
                else { return }
            do {
                try FileManager.default.moveItem(at: location, to: fileURL)

                let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
                let audioDuration = asset.duration
                let audioDurationSeconds = CMTimeGetSeconds(audioDuration)

                self.elapsedTimeInSecond = Int(audioDurationSeconds)

                DispatchQueue.main.async {
                    self.updateTimeLabel()
                    self.startTimer()
                }

                self.audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
                self.audioPlayer?.delegate = self
                self.audioPlayer?.play()

            } catch {
                print(error)
            }
        }).resume()
    }
}

func startTimer() {

    timer?.invalidate()
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { (timer) in
        self.elapsedTimeInSecond -= 1
        self.updateTimeLabel()
    })
}

func resetTimer(second:Int) {
    timer?.invalidate()
    elapsedTimeInSecond = second
    updateTimeLabel()
}

func updateTimeLabel() {

    let seconds = elapsedTimeInSecond % 60
    let minutes = (elapsedTimeInSecond/60) % 60

    mySecondLabel.isHidden = false
    mySecondLabel.text = String(format: "%02d:%02d", minutes,seconds)
}
}

extension TableViewCell:AVAudioPlayerDelegate {

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {

    let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Id)/Record/")
    let fileName = message?.content.substring(from: 62)
    let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)

    if FileManager.default.fileExists(atPath: fileURL.path) {

        let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
        let audioDuration = asset.duration
        let audioDurationSeconds = CMTimeGetSeconds(audioDuration)

        DispatchQueue.main.async {
            self.resetTimer(second: Int(audioDurationSeconds))
            self.myRecordPlayerBtn.imageView!.stopAnimating()
            self.myRecordPlayerBtn.imageView?.image = #imageLiteral(resourceName: "img_myRocordDefault")
        }
    }
}
}

可能首先初始化以检查您的播放器是否正在播放

if audioPlayer != nil{
            if audioPlayer?.isPlaying == true {

                audioPlayer?.stop()

                DispatchQueue.main.async {
                    self.resetTimer(second: self.elapsedTimeInSecond)
                    self.startTimer()
                }

            }
        }

如果你不想同时播放两个音轨,你应该使用 AVAudioPlayer 的共享实例 这对性能会更好,您可以在控制器中将实例定义为 static var。它可以在每个单元格中访问。

我开发了一个音乐播放器应用程序,我在 MusicPlay 管理器中使用了一个共享实例:

class MusicPlayManager{

  var player : AVAudioPlayer?

  static let sharedInstance = MusicPlayManager.init()

  private override init() {
        super.init()

    }

 // something else, such as palyNext, playPrevious methods
}

在您的 viewController 中,您可以使用 MusicPlayManager.sharedInstance.player