Calling function from another ViewController in swift

51,348

Solution 1

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 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 class:

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

Solution 2

Swift 5:

Put this in the Action

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

Put this in viewdidload() in a different viewcontroller (where is the function you want to use)

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

The function

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

I hope I was helpful

Solution 3

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

Solution 4

I use this way to call my functions from another viewControllers:

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

Solution 5

You can call function from other viewControllers in many ways.

Two ways that are already discussed above are by delegates & protocols and by sending notifications.

Another way is by passing closures to your second viewController from firstVC.

Below is the code in which while segueing to SecondVC we pass a closure to stop the metronome. There will be no issue because you are passing the same firstVC (not creating a new instance), so the metronome will not be nil.

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
      }

   }

 }
Share:
51,348
Andyopf
Author by

Andyopf

Updated on September 13, 2020

Comments

  • Andyopf
    Andyopf over 3 years

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