Calling function from another ViewController in swift
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
}
}
}
Andyopf
Updated on September 13, 2020Comments
-
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)" } }