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() 放入两个动作pPressedp2Pressed 我知道了,但是如果我需要添加两个以上的players 怎么办?进入我的private functions?这是怎么回事? @Shahin, 你可以使用thirdSoundTimer, fourthSoundTimer,... 或者可能有其他一些方法。但你真的需要吗?如果你真的需要它,你最好为它启动一个新线程。我相信有很多人可以回答它。 是的,我需要它,你是对的,感谢您的时间和信息

以上是关于Swift:多个函数同时工作的主要内容,如果未能解决你的问题,请参考以下文章

如何限制同时调用函数的多个定时器函数? Swift 3+

一个 UIView Swift 中的多个 TableViews - 如何同时显示

Swift 4 AVFoundation - 同时录制多个音频源

使用 Swift 在单个 UIView 上同时进行多个动画

Swift COW 线程安全

Swift 清除特定的远程通知