Как последовательно запустить функцию в цикле for
У меня есть набор кнопок в виде стека. Каждая кнопка при нажатии воспроизводит другой звук. У меня есть отдельная кнопка (кнопка цикла), которая при нажатии вызываетloopButtonPressed
функция. Моя цель состоит в том, чтобы при нажатии этой кнопки цикла он перебирал подпредставления, которые являются кнопками в этом представлении стека, и последовательно воспроизводил каждый из звуков, используяsoundButtonPressed
функция. Я видел метод, который реализовал ниже, используяrun()
функция, которая устанавливает каждую последующую функцию для запуска через заданный промежуток времени. Хотя такой вид работает, это не лучшее решение, потому что звуковые файлы имеют разную длину. Я думал, что есть способ сделать это с помощью групп отправки, чего я не совсем понимаю. Если я уберу функцию запуска, она будет воспроизводить только звук последней кнопки в представлении стека. Я также использую AVFoundation для воспроизведения файлов wav. Я ценю любой совет или направление, спасибо.
func run(after seconds: Int, completion: @escaping () -> Void) {
let deadline = DispatchTime.now() + .milliseconds(seconds)
DispatchQueue.main.asyncAfter(deadline: deadline) {
completion()
}
}
@objc func loopButtonPressed(_ sender: UIButton) {
var i = 1
for case let button as UIButton in self.colorBubblesStackView.subviews {
run(after: 800*i) {
self.soundButtonPressed(sender: button)
}
i += 1
}
}
Моя функция soundButtonPressed - это просто оператор switch, в котором каждый случай вызывает функцию playSound()
с правильным именем звукового файла. Вот функция playSound:
func playSound(_ soundFileName: String) {
guard let url = Bundle.main.url(forResource: soundFileName, withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
2 ответа
func playSound(name: String ) {
guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
print("url not found")
return
}
do {
/// this codes for making this app ready to takeover the device audio
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
/// change fileTypeHint according to the type of your audio file (you can omit this)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
player?.delegate = self
// no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
player!.play()
} catch let error as NSError {
print("error: \(error.localizedDescription)")
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finished")//It is working now! printed "finished"!
}
подтвердить протокол
class ViewController: UIViewController,AVAudioPlayerDelegate {
и вместо цикла добавьте к каждой кнопке тег и начните с первого тега, набранного 100 . Затем, когда обратный вызов, полученный для игрока, завершил воспроизведение, воспроизведите следующий файл с новым тегом icremented, скажем, 101
Пытаться AVQueuePlayer
Раньше игрок последовательно проигрывал несколько предметов.
@objc func loopButtonPressed(_ sender: UIButton) {
let allUrls = allSongs.compactMap { Bundle.main.url(forResource: $0, withExtension: "wav") }
let items = allUrls.map { AVPlayerItem(url: $0) }
let queuePlayer = AVQueuePlayer(items: items)
queuePlayer.play()
}