在swift中从另一个ViewController调用函数

时间:2017-02-09 11:23:48

标签: ios swift avplayer

我已经查看了Stackoverflow,但我无法得到答案。我想创建停止在另一个ViewController中播放声音的函数。但是当我点击停止按钮时,它会破解并显示" EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)"。这是我的代码。

First ViewController

import UIKit
import AVFoundation

class FirstVC: UIViewController {

   var metronome: AVAudioPlayer!
   override func viewDidLoad() {
       super.viewDidLoad()
   do {
        let resourcePath1 = Bundle.main.path(forResource: "music", ofType: "mp3")
        let url = NSURL(fileURLWithPath: resourcePath1!)
        try metronome = AVAudioPlayer(contentsOf: url as URL)

        metronome.prepareToPlay()
        metronome.play()
    } catch let err as NSError {
        print(err.debugDescription)
    }
}

和另一个Viewcontroller是

import UIKit
class SecondVC: UIViewController {
   var metronomePlay = FirstVC()

@IBAction func stopBtnPressed(_ sender: Any) {
   metronomePlay.metronome.stop() //"EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
   }
}

11 个答案:

答案 0 :(得分:13)

您正在创建FirstVC的新副本,并在尚未初始化的内容上调用stop。

在这种情况下,您应该使用委托,例如

protocol controlsAudio {
   func startAudio()
   func stopAudio()
}

class FirstVC: UIViewController, controlsAudio {
    func startAudio() {}
    func stopAudio() {}

    // later in the code when you present SecondVC
    func displaySecondVC() {
       let vc = SecondVC()
       vc.delegate = self
       self.present(vc, animated: true)
    }

}

class SecondVC: UIViewController {
    var delegate: controlsAudio?

    // to start audio call self.delegate?.startAudio)
    // to stop audio call self.delegate?.stopAudio)

}

因此,您将第一个VC传递给第二个VC,因此当您调用这些函数时,您正在使用正在使用的实际FirstVC上,而不是创建一个新函数。

如果您愿意,可以将var delegate: controlsAudio?替换为var firstVC: FirstVC?并指定,但我不建议

答案 1 :(得分:10)

从今天的swift 4.1开始,这段代码对我有用:

把它放在发送控制器中:

NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)

把它放在接收控制器viewDidLoad()或viewWillAppear()中:

NotificationCenter.default.addObserver(self, selector: #selector(disconnectPaxiSocket(_:)), name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)

然后接收控制器类中的以下函数:

@objc func disconnectPaxiSocket(_ notification: Notification) {
    ridesTimer.invalidate()
    shared.disconnectSockets(socket: self.socket)
}

答案 2 :(得分:4)

迅速5:

将其放入操作

NotificationCenter.default.post(name: Notification.Name("NewFunctionName"), object: nil)

将其放在其他viewcontroller的viewdidload()中(您要使用的函数在哪里)

NotificationCenter.default.addObserver(self, selector: #selector(functionName), name: Notification.Name("NewFunctionName"), object: nil)

功能

 @objc func functionName (notification: NSNotification){ //add stuff here}

我希望我能帮上忙

答案 3 :(得分:3)

我使用这种方式从另一个viewControllers调用函数:

let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);

答案 4 :(得分:2)

更新@Scriptable的答案 Swift 4

第1步:

在视图控制器中添加此代码,您可以从中按下按钮以停止声音。

@IBAction func btnStopSound(_ sender: AnyObject)
{
    notificationCenter.post(name: Notification.Name("stopSoundNotification"), object: nil)

}

第2步:

现在是最后一步。现在将以下代码添加到结果视图控制器中,您希望自动停止声音。

func functionName (notification: NSNotification) {
           metronomePlay.metronome.stop()
}

override func viewWillAppear(animated: Bool) {
           NSNotificationCenter.defaultCenter().addObserver(self, selector: "functionName",name:"stopSoundNotification", object: nil)

}

答案 5 :(得分:1)

var metronomePlay = FirstVC()

您正在FirstVC上创建一个新实例,而应该在已加载FirstVC的同一实例上执行该功能。

答案 6 :(得分:0)

您正在使用metronome viewDidLoad方法初始化FirstVC。 在SecondVC中,您将metronomePlay初始化为存储属性,但从不要求ViewController的视图,因此viewDidLoad的{​​{1}}未被调用,导致{{1} (存储的属性)没有初始化。

答案 7 :(得分:0)

您在metronome的{​​{1}}上初始化FirstVC,在viewDidLoad加载metronomePlay实例化视图之前,这不会发生。

在实际调用SecondVC之前,您必须致电_ = metronomePlay.view,它会懒惰地加载SecondVC的视图并随后执行viewDidLoad

答案 8 :(得分:0)

使用通知进程从任何地方停止或使用SecondVC类中的相同FirstVC实例。

答案 9 :(得分:0)

您可以通过多种方式从其他viewController调用函数。

上面已经讨论的两种方法是通过委托人和协议以及通过发送通知。

另一种方法是将闭包从firstVC传递到第二个viewController。

以下是在代码中选择SecondVC时,我们传递一个闭包以停止节拍器的代码。 不会有问题,因为您传递的是相同的firstVC(而不是创建新实例),因此节拍器不会为零。

class FirstVC: UIViewController {

   var metronome: AVAudioPlayer!
   override func viewDidLoad() {
      super.viewDidLoad()
      do {
           let resourcePath1 = Bundle.main.path(forResource: "music", ofType: "mp3")
           let url = NSURL(fileURLWithPath: resourcePath1!)
           try metronome = AVAudioPlayer(contentsOf: url as URL)

           metronome.prepareToPlay()
           metronome.play()
        } catch let err as NSError {
            print(err.debugDescription)
        }

      let secondVC = SecondVC()
      secondVC.stopMetronome = { [weak self] in
        self?.metronome.stop()
      }
      present(secondVC, animated: true)

    }
}


class SecondVC: UIViewController {
   var metronomePlay = FirstVC()
   var stopMetronome: (() -> Void)? // stopMetronome closure

   @IBAction func stopBtnPressed(_ sender: Any) {
      if let stopMetronome = stopMetronome {
         stopMetronome() // calling the closure
      }

   }

 }

答案 10 :(得分:-1)

在SecondVC中尝试此操作。 var metronomePlay = FirstVC()。节拍器