Calling function from another ViewController in swift

匿名 (未验证) 提交于 2019-12-03 03:06:01

问题:

I have already looked in Stackoverflow but I can't get an answer. I want to create function that stop playing the sound in another ViewController. But when I clicked the stop button, it cracked and showed "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)". This is my code.

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)     } }

and another Viewcontroller is

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)"    } }

回答1:

You are creating a NEW copy of FirstVC and calling stop on something that is not yet initialised.

You should really use a delegate in this case, something like

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)  }

So you are passing first VC to the second VC, so when you call these functions you are doing it on the actual FirstVC that is in use, rather than creating a new one.

You could do this without protocols if you like by replacing the var delegate: controlsAudio? with var firstVC: FirstVC? and assigning that, but I wouldn't recommend it



回答2:

Updating @Scriptable's answer for Swift 4

Step 1 :

Add this code in your view controller, from which you want to press button click to stop sound.

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

Step 2:

Now its final step. Now add this below code, to your result view controller, where you want to automatically stop sound.

func functionName (notification: NSNotification) {            metronomePlay.metronome.stop() }  override func viewWillAppear(animated: Bool) {            NSNotificationCenter.defaultCenter().addObserver(self, selector: "functionName",name:"stopSoundNotification", object: nil)  }


回答3:

You are initialising metronome in viewDidLoad method of FirstVC. In SecondVC, you are initialising metronomePlay as a stored property, but never asking for ViewController's view and thus viewDidLoad of FirstVC is not getting called which results in metronome(stored property) not getting initialised.



回答4:

Either use the notification process to stop from anywhere or use same FirstVC instance from SecondVC class.



回答5:

As of swift 4.1 today, this code worked for me:

Put this in sending controller:

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

Put this in receiving controller's viewDidLoad() or viewWillAppear():

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

and then the following function in your receiving controller's class:

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


回答6:

You initialize metronome on FirstVC in viewDidLoad, which won't happen until you load the view of metronomePlay instantiated in SecondVC.

You have to call _ = metronomePlay.view, which will lazily load the view of SecondVC and subsequently execute viewDidLoad, before actually calling metronomePlay.metronome.



回答7:

var metronomePlay = FirstVC()

you are creating a new instance on FirstVC, instead you should perform the function on the same instance that of already loaded FirstVC.



回答8:

Try this in SecondVC. var metronomePlay = FirstVC().metronome



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!