Swift:多个函数同时工作
Posted
技术标签:
【中文标题】Swift:多个函数同时工作【英文标题】:Swift: multiple functions working at the same time 【发布时间】:2017-08-15 23:32:08 【问题描述】:在我的应用程序中,我有 2 个 UIButton,每个按钮播放 2 种声音(播放一种声音、暂停、播放另一种声音),每次按下时 UIButtons 图像都会发生变化,我的应用程序也有一些选项卡。问题是当我按下 UIButton (播放和完成声音大约需要 4 秒)时,我无法按下另一个按钮,甚至无法在选项卡之间切换,应用程序冻结,直到 UIbutton 的操作完成,然后我可以按其他按钮或切换标签。 这是我的代码:
import UIKit
import AVFoundation
import CoreData
class FirstViewController: UIViewController
var player:AVAudioPlayer = AVAudioPlayer()
var player2:AVAudioPlayer = AVAudioPlayer()
@IBAction func play(_ sender: Any)
player.play()
sleep(1)
player2.play()
@IBAction func play2(_ sender: Any)
player.play()
sleep(1)
player2.play()
@IBOutlet weak var play: UIButton!
@IBOutlet weak var play2: UIButton!
var buttonActive = false
@IBAction func pPressed(_ sender: Any)
if buttonActive
play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
else
play.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
buttonActive = !buttonActive
@IBAction func p2Pressed(_ sender: Any)
if buttonActive
play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
else
play2.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
buttonActive = !buttonActive
override func viewDidLoad()
super.viewDidLoad()
play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
do
let audioPath = Bundle.main.path(forResource: "DTMF-1", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
let audioPath2 = Bundle.main.path(forResource: "DTMF-2", ofType: "mp3")
try player2 = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath2!) as URL)
有什么方法可以让我的应用更快?
【问题讨论】:
最重要的是不能在主线程中调用sleep(_:)
。而且你的问题还不够清楚。只需两个按钮,您就有四个动作。您如何将每个按钮与操作联系起来?而句子它们一次只工作一个,AVAudioPlayer
可以一次播放一个声音,你需要同时播放 button1 的声音和 button2 的声音吗?或者您可以在按下按钮2时停止按钮1的声音?
我编辑了我的问题。
你真的更新了你的问题,没有回答我的问题......
我已经通过 Touch Up Inside 事件将它们连接到 UIButton 的操作,它们工作得很好。我知道AVAudioPlayer
只能播放一个,我希望它在我按下另一个按钮时停止,或者当我切换标签时,我不希望应用程序冻结并等待AVAudioPlayer
完成然后开始工作,我希望 AVAudioPlayer 在我在应用程序中执行其他操作时继续工作。
我的第二个问题已经很清楚了。但不是我的第一个。哪个按钮执行哪个操作? (这是命令。)您正在使用 freeze-my-app 功能之一,它被命名为sleep
。
【参考方案1】:
实现做某事、暂停和做其他事情的一种著名方法是使用Timer
。
以下代码还包括:
如何正确实例化AVAudioPlayer
如何使工作无效Timer
如何stop
AVAudioPlayer
可能很快会被重复使用
如何在过渡时停止播放
请尝试:
class FirstViewController: UIViewController
var player: AVAudioPlayer? //### You should not instantiate unused objects
var player2: AVAudioPlayer?
var secondSoundTimer: Timer?
private func startPlaying()
stopPlaying()
player?.play()
//### Using `Timer` is one way to achieve pause-like thing.
//### If you need to target older ioss than 10.0, you need to modify this part.
secondSoundTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) timer in
self.player2?.play()
self.secondSoundTimer?.invalidate()
self.secondSoundTimer = nil
private func stopPlaying()
secondSoundTimer?.invalidate()
secondSoundTimer = nil
if let player = player, player.isPlaying
//### Stop playing (keeping internal `prepared` state) and rewind to the first place.
player.pause()
player.currentTime = 0
if let player2 = player2, player2.isPlaying
player2.pause()
player2.currentTime = 0
@IBOutlet weak var play: UIButton!
@IBOutlet weak var play2: UIButton!
var buttonActive = false
@IBAction func pPressed(_ sender: Any)
startPlaying()
if buttonActive
play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
else
play.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
buttonActive = !buttonActive
//### Don't you need `button2Active`?
@IBAction func p2Pressed(_ sender: Any)
startPlaying()
if buttonActive
play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
else
play2.setBackgroundImage(UIImage(named: "Switch-Icon-40"), for: .normal)
buttonActive = !buttonActive
override func viewDidLoad()
super.viewDidLoad()
play.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
play2.setBackgroundImage(UIImage(named: "SwitchD-Icon-40"), for: .normal)
do
//### You can get URL directly from Bundle
//### It's better to apply forced-unwrapping as soon as possible, if you need it eventually.
let audioURL = Bundle.main.url(forResource: "DTMF-1", withExtension: "mp3")!
player = try AVAudioPlayer(contentsOf: audioURL)
//### `prepareToPlay()` improves response for the first play.
player?.prepareToPlay()
let audioURL2 = Bundle.main.url(forResource: "DTMF-2", withExtension: "mp3")!
player2 = try AVAudioPlayer(contentsOf: audioURL2)
player2?.prepareToPlay()
catch
print(error)
//... or any other things you need...
//...
//### Stop playing on transition to other ViewConrollers.
override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(animated)
stopPlaying()
【讨论】:
@Shahin,对不起,我应该在回答中提到它。将多个动作连接到单个按钮很容易导致意外行为,因此我删除了这两个动作。要测试我的代码,您需要删除两个操作连接——play
按钮到play
操作和play2
按钮到play2
操作。相反,我将startPlaying()
放入两个动作pPressed
和p2Pressed
。
我知道了,但是如果我需要添加两个以上的player
s 怎么办?进入我的private function
s?这是怎么回事?
@Shahin, 你可以使用thirdSoundTimer
, fourthSoundTimer
,... 或者可能有其他一些方法。但你真的需要吗?如果你真的需要它,你最好为它启动一个新线程。我相信有很多人可以回答它。
是的,我需要它,你是对的,感谢您的时间和信息以上是关于Swift:多个函数同时工作的主要内容,如果未能解决你的问题,请参考以下文章
一个 UIView Swift 中的多个 TableViews - 如何同时显示