Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling function from another ViewController in swift

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)"
   }
}
like image 947
Andyopf Avatar asked Feb 09 '17 11:02

Andyopf


People also ask

How do I call a function in another swift file?

In order to use a function in one swift file to another: just create the object of the class file you want to use the function from.

How can I call viewDidLoad from another ViewController?

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

How do I pass data from one ViewController to another view controller in Swift?

Control + click the UI element you are going to use to make the bridge and drag to the second View Controller. Select the “Show” option from the “Action Segue” menu. Control + click the button and drag to the second ViewController, then select “Show.”


3 Answers

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)
}
like image 85
shanezzar Avatar answered Nov 13 '22 07:11

shanezzar


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

like image 25
Romy Avatar answered Nov 13 '22 09:11

Romy


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

like image 21
Scriptable Avatar answered Nov 13 '22 08:11

Scriptable