Swift:多功能问题

Swift: Multi-Function issue

我有 999(从 000 到 999)个数字作为 ints,它们都打印在 UILabel 上,我也得到 UILabel 的值更新为updateCurrentValue 并且当我按下 UIButton 进行宣布 function 时必须宣布所有数字,数字的声音分别通过 AVFoundation 和宣布代码导入(例如)数字 15 是:

if currentValue == 15 {
Sound15?.play()
}

现在我正在寻找一种代码,它可以让数百人更容易,因为为所有 999 个数字制作 function 会浪费时间。有什么方法可以让我只能给出数百个数字中的 value,然后它会自动为其余数字自动找到 func?我希望我能说清楚,以便有人可以回答。到目前为止,这是我得到的:

import UIKit
import AVFoundation

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

var Sound1:AVAudioPlayer?
var Sound2:AVAudioPlayer?
var Sound3:AVAudioPlayer?
var Sound4:AVAudioPlayer?
var Sound5:AVAudioPlayer?
var Sound6:AVAudioPlayer?
var Sound7:AVAudioPlayer?
var Sound8:AVAudioPlayer?
var Sound9:AVAudioPlayer?
var Sound10:AVAudioPlayer?
var Sound11:AVAudioPlayer?
var Sound12:AVAudioPlayer?
var Sound13:AVAudioPlayer?
var Sound14:AVAudioPlayer?
var Sound15:AVAudioPlayer?
var Sound16:AVAudioPlayer?
var Sound17:AVAudioPlayer?
var Sound18:AVAudioPlayer?
var Sound19:AVAudioPlayer?
var Sound20:AVAudioPlayer?
var Sound30:AVAudioPlayer?
var Sound40:AVAudioPlayer?
var Sound50:AVAudioPlayer?
var Sound60:AVAudioPlayer?
var Sound70:AVAudioPlayer?
var Sound80:AVAudioPlayer?
var Sound90:AVAudioPlayer?
var Sound100:AVAudioPlayer?
var Sound200:AVAudioPlayer?
var Sound300:AVAudioPlayer?
var Sound400:AVAudioPlayer?
var Sound500:AVAudioPlayer?
var Sound600:AVAudioPlayer?
var Sound700:AVAudioPlayer?
var Sound800:AVAudioPlayer?
var Sound900:AVAudioPlayer?

var currentValue = 0

func updateCurrentValue() {
    let hundreds = max(0, pickerView.selectedRow(inComponent: 0))
    let tens = max(0, pickerView.selectedRow(inComponent: 1))
    let ones = max(0, pickerView.selectedRow(inComponent: 2))

    currentValue = hundreds * 100 + tens * 10 + ones
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 3
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return String(row)
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 10 // digits 0 - 9
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    updateCurrentValue()

    changeLabelText()
}

//Some Functions as example of how it works:

private func accouncingNumbers() {

//for single digit

if currentValue == 1 {
Sound1?.play()
}

//for double digits

if currentValue == 24 {
Sound20?.play()
SoundTimer = Timer.scheduledTimer(withTimeInterval: 1.2, repeats: false) {timer in
    self.Sound4?.play()
    self.SoundTimer?.invalidate()
    self.SoundTimer = nil
}
}

//for 3-digits

if currentValue == 146 {
Sound100?.play()
SoundTimer = Timer.scheduledTimer(withTimeInterval: 1.2, repeats: false) {timer in
    self.Sound40?.play()
    self.SoundTimer?.invalidate()
    self.SoundTimer = nil
    self.SoundTimer = Timer.scheduledTimer(withTimeInterval: 1.2, repeats: false) {timer in
        self.Sound6?.play()
        self.SoundTimer?.invalidate()
        self.SoundTimer = nil
    }
}
}

 //Sounds imported here

    do

  {
    let audioURL1 = Bundle.main.url(forResource: "1", withExtension: "mp3")!
    Sound1 = try AVAudioPlayer(contentsOf: audioURL1)
    Sound1?.prepareToPlay()


  }


  catch

  {
     print(error)
    }

}

只是想为这个过程找到一个更简单、更短的方法。

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

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 重新加载正确的波形文件,开始播放,当当前声音播放完毕后,加载队列中的下一个波形文件并播放直到队列为空。根据您的要求,您可能希望能够中止播放、刷新公告队列等。

或者,您可以为支持范围内的每个数字创建一个波形文件,并简单地将它们编号为 say_0.mp3 至 say_999.mp3;如果您开始支持更大的数字(100 万 307 万 5 千 6 八八),就会变得非常乏味

这是一个完整的示例:

//
//  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。代码应该很容易适应任何长度的数字。