使用AVAudioPlayer在iOS中使用Swift:Singleton没有像我希望的那样工作

时间:2016-07-28 16:29:54

标签: ios swift singleton avaudioplayer

我正在使用标准的Master-Detail项目,在Master中列出歌曲并在Detail中播放。每首歌曲最多有四个部分同时播放,具有独立的音量控制,因此我有四个AVAudioPlayer对象详细信息,每个对象都有一个带有IBOutlet的滑块和一个用于实现音量控制的IBAction。

问题是,当您点击一首歌曲(在主人的列表中)时,前一首歌曲不会停止。虽然音量控制现在只控制最近的歌曲,但两首歌曲都会播放。这可以继续播放任意数量的歌曲。

我希望在点击新歌时摆脱当前正在播放的歌曲。

我认为我可以通过在Singleton中创建玩家来实现这一目标,这样只会有四个玩家。因为,根据文档,每个播放器一次只能播放一个声音文件,我希望以前的声音文件在新的声音文件启动时停止播放。但它不起作用。上述相同的行为仍在发生:多首歌曲可以同时播放,音量控制仅控制最近的歌曲。任何建议都将不胜感激。

以下是Singleton的代码:

import Foundation
import AVFoundation

class FourPlayers {
       static let audioPlayers = [one, two, three, four]

        static let one = AVAudioPlayer()
        static let two = AVAudioPlayer()
        static let three = AVAudioPlayer()
        static let four = AVAudioPlayer()

        private init() {} //This prevents others from using the default '()' initializer for this class.
}

(最初,我刚刚将audioPlayers设为静态,但是当它不起作用时,我决定让每个玩家都保持静态。)

然后,在DetailViewController中:

var audioPlayers = FourPlayers.audioPlayers

以下是四个音量控件之一的代码:

@IBOutlet weak var vol1: UISlider!

@IBAction func volAdjust1(sender: AnyObject) {
    audioPlayers[0].volume = vol1.value
}

播放一首歌是这样的(当歌曲信息从Master传入时,audioFiles数组被填充):

var audioFiles = []

func  playAudioFiles() {
    var i = 0
    for _ in audioFiles {
        audioPlayers[i].play()
        i+=1
    }
}

这是告诉玩家要播放哪个文件的代码:

func prepareAudioFiles () {
    var i = 0;
    for audioFile in audioFiles {
        let s = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(audioFile as? String, ofType: "mp3")!)
        do {
            audioPlayers[i] = try AVAudioPlayer(contentsOfURL:s)
        } catch {
            print("Error getting the audio file")
        }
        audioPlayers[i].prepareToPlay()
        self.audioPlayers[i].delegate = self
    }
}

2 个答案:

答案 0 :(得分:0)

似乎音量控制仅调整第一个玩家(索引0)

@IBAction func volAdjust1(sender: AnyObject) {
    audioPlayers[0].volume = vol1.value
}

也许你可以添加一个变量来跟踪当前正在播放的索引

var currentlyPlayingIndex = 0
@IBAction func volAdjust1(sender: AnyObject) {
    audioPlayers[currentlyPlayingIndex].volume = vol1.value
}

并在需要时更新

播放音频时,您可以使用相同的变量

func  playAudioFiles() {
    var i = 0
    for _ in audioFiles {

        if i == currentlyPlayingIndex {
            audioPlayers[i].play()
        } else {
            audioPlayers[i].stop()
        }
        i+=1
    }
}

答案 1 :(得分:0)

问题在于以下几行:

<table ng-table="vm.tableParams" class="table" show-filter="true">
    <tr ng-repeat="user in $data">
        <td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
            {{user.name}}</td>
        <td title="'Age'" filter="{ age: 'number'}" sortable="'age'">
            {{user.age}}</td>
    </tr>
</table>

您实际上是在AudioPlayers变量中创建FourPlayers.audioPlayers数组的新副本。因此,您不会重复使用AVAudioPlayers,而是为每首歌创建独立的。

请参阅&#34;字符串,数组和字典的分配和复制行为&#34; Swift Programming Documentation, Classes and Structures

中的部分

您可以直接在代码中使用静态变量,而不是制作副本,例如:

var self = this;
var data = [{name: "Moroni", age: 50},{name: "Moroni", age: 50},{name: "Moroni", age: 50},{name: "Moroni", age: 50},{name: "Moroni", age: 50},{name: "Moroni", age: 50}];
self.tableParams = new NgTableParams({}, { dataset: data});

var audioPlayers = FourPlayers.audioPlayers

并相应地更新其余代码。