Swift:多功能问题

时间:2017-09-20 19:51:31

标签: ios swift avaudioplayer

我有{9}(从000到999)的数字为int,并且它们都打印在UILabel上,我还将UILabel的值更新为{{当我按下发出updateCurrentValue的{​​{1}}时,必须公布所有数字,并通过UIButton和声明代码导入数字的声音(例如)数字15是:

function

现在我正在寻找能够让数百人更轻松的代码,因为对于所有999个数字来说,AVFoundation是一个浪费时间。有什么方法我只能给出数百的if currentValue == 15 { Sound15?.play() } 然后它会自动找到其余数字的function吗?我希望我能说清楚,以便有人能回答。这是我到目前为止所得到的:

value

只是想为这个过程找到一种更简单,更短的方式。

1 个答案:

答案 0 :(得分:3)

为了最大限度地减少您需要在应用程序中捆绑的声音文件数量,您需要一个类似于此的算法:

func verbalizeValue(_ value: Int) {
    let announcements = prepareAnnouncements(value)
    playAnnouncements(announcements)
}

func prepareAnnouncements(_ value: Int) -> [String] {
    var valueToProcess: Int = value
    var announcements: [String] = []
    if valueToProcess >= 100 {
        // values 100 and above
        let hundred = valueToProcess / 100
        valueToProcess = valueToProcess % 100
        let soundfile = "say_\(hundred)00.wav"
        announcements.append(soundfile)
    }
    if valueToProcess >= 20 {
        // values 30 to 99
        let dozen = valueToProcess / 10
        valueToProcess = valueToProcess % 10
        let soundfile = "say_\(dozen)0.wav"
        announcements.append(soundfile)
    }
    if valueToProcess > 1 || announcements.count == 0 {
        // values 0 to 19
        let soundfile = "say_\(value).wav"
        announcements.append(soundfile)
    }
    return announcements
}

func playAnnouncements(_ announcements: [String] ) {
    // announcements contains an array of wave filenames to play one after the other
}

然后,您可以使用单个AVAudioPlayer,使用正确的波形文件重新加载,开始播放,当前声音播放完毕,加载队列中的下一个波形文件并播放直到队列为空。根据您的要求,您可能希望能够中止播放,刷新公告队列等等。

或者,您可以为支持范围内的每个数字创建一个wave文件,只需将它们编号为say_0.mp3 to say_999.mp3;如果你开始支持更大的数字(100万3和75万,六百八十八),那真的很乏味

这是一个完整的例子:

//
//  ViewController.swift
//  SayNumber
//
//  Created by Dave Poirier on 2017-09-21.
//  Copyright © 2017 Soft.io. All rights reserved.
//

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {

    var valueToAnnonce: Int = 321
    var audioPlayer: AVAudioPlayer!
    var audioQueue: [String] = []

    @IBAction
    func announceValue(_ sender: Any?) {
        verbalizeValue(valueToAnnonce)
    }

    func verbalizeValue(_ value: Int) {
        let announcements = prepareAnnouncements(value)
        playAnnouncements(announcements)
    }

    func prepareAnnouncements(_ value: Int) -> [String] {
        var valueToProcess: Int = value
        var announcements: [String] = []
        if valueToProcess >= 100 {
            // values 100 and above
            let hundred = valueToProcess / 100
            valueToProcess = valueToProcess % 100
            let soundfile = "say_\(hundred)00"
            announcements.append(soundfile)
        }
        if valueToProcess >= 20 {
            // values 30 to 99
            let dozen = valueToProcess / 10
            valueToProcess = valueToProcess % 10
            let soundfile = "say_\(dozen)0"
            announcements.append(soundfile)
        }
        if valueToProcess >= 1 || announcements.count == 0 {
            // values 0 to 19
            let soundfile = "say_\(valueToProcess)"
            announcements.append(soundfile)
        }
        return announcements
    }

    func playAnnouncements(_ announcements: [String] ) {
        // announcements contains an array of wave filenames to play one after the other
        if nil != audioPlayer && audioPlayer!.isPlaying {
            print("Audio player was active, stop it and play the new announcements!")
            audioPlayer.stop()
        }
        audioQueue.removeAll()
        for filename in announcements {
            let path = pathForAudioFile(filename)
            if path != nil {
                audioQueue.append(path!)
            }
        }
        playNextInQueue()
    }

    func playNextInQueue() {
        let nextPathInQueue = audioQueue.first
        if nextPathInQueue != nil {
            audioQueue.removeFirst(1)
            let audioFileURL = URL(fileURLWithPath: nextPathInQueue!)
            audioPlayer = try? AVAudioPlayer(contentsOf: audioFileURL)
            guard audioPlayer != nil else {
                print("Oops, file not found: \(nextPathInQueue!)")
                return
            }
            print("playing \(nextPathInQueue!)")
            audioPlayer?.delegate = self
            audioPlayer?.play()
        } else {
            print("looks like we are all done!")
        }
    }

    func pathForAudioFile(_ filename: String) -> String? {
        return Bundle.main.path(forResource: filename, ofType: "wav")
    }

    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        DispatchQueue.main.async {
            self.playNextInQueue()
        }
    }
}

在按下按钮的控制台日志中,可以看到以下内容:

playing /var/containers/Bundle/Application/E2D5E7AD-26B4-4BBA-B52C-B91B62BA7161/SayNumber.app/say_300.wav
playing /var/containers/Bundle/Application/E2D5E7AD-26B4-4BBA-B52C-B91B62BA7161/SayNumber.app/say_20.wav
playing /var/containers/Bundle/Application/E2D5E7AD-26B4-4BBA-B52C-B91B62BA7161/SayNumber.app/say_1.wav
looks like we are all done!

控制器期望音频文件say_0.wav通过say_19.wav,然后每隔几十个从say_20.wav到say_90.wav,然后数百个从say_100.wav到say_900.wav。代码应该易于适应任何长度的数字。