Swift:多功能问题
Swift: Multi-Function issue
我有 999(从 000 到 999)个数字作为 int
s,它们都打印在 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。代码应该很容易适应任何长度的数字。
我有 999(从 000 到 999)个数字作为 int
s,它们都打印在 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。代码应该很容易适应任何长度的数字。