web-dev-qa-db-fra.com

Appel de la fonction depuis un autre ViewController en swift

J'ai déjà regardé dans Stackoverflow mais je ne peux pas obtenir de réponse. Je veux créer une fonction qui arrête la lecture du son dans un autre ViewController. Mais lorsque j'ai cliqué sur le bouton d'arrêt, il s'est fissuré et a affiché "EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, sous-code = 0x0)". Ceci est mon code.

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

et un autre Viewcontroller est

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

Vous créez une NOUVELLE copie de FirstVC et appelez un arrêt sur quelque chose qui n’a pas encore été initialisé.

Vous devriez vraiment utiliser un délégué dans ce cas, quelque chose comme 

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)

}

Ainsi, vous passez le premier VC au deuxième VC. Ainsi, lorsque vous appelez ces fonctions, vous le faites sur le FirstVC en cours d'utilisation plutôt que d'en créer une nouvelle. 

Vous pouvez le faire sans protocoles si vous voulez en remplaçant le var delegate: controlsAudio? par le var firstVC: FirstVC? et en l'attribuant, mais je ne le recommanderais pas.

12
Scriptable

Depuis Swift 4.1 aujourd'hui, ce code fonctionnait pour moi:

Mettez ceci dans le contrôleur d'envoi:

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

Placez ceci dans le contrôleur de réception viewDidLoad () ou viewWillAppear ():

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

puis la fonction suivante dans votre classe de contrôleur de réception:

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

Mise à jour de la réponse de @ Scriptable pour Swift 4

Étape 1 :

Ajoutez ce code dans votre contrôleur de vue, à partir duquel vous souhaitez appuyer sur le clic du bouton pour arrêter le son.

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

}

Étape 2:

Maintenant sa dernière étape. Maintenant, ajoutez ce code ci-dessous, à votre contrôleur de vue des résultats, où vous souhaitez arrêter automatiquement le son.

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

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

}
2
Alex Bailey

J'utilise cette façon d'appeler mes fonctions depuis un autre viewControllers:

let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);
1
Minas Petterson
var metronomePlay = FirstVC()

vous créez une nouvelle instance sur FirstVC, vous devez plutôt exécuter la fonction sur la même instance que celle de FirstVC déjà chargé. 

0
Emel Elias

Utilisez le processus de notification pour arrêter de n'importe où ou utilisez la même instance FirstVC de la classe SecondVC.

0
Zoeb S

Vous initialisez metronome sur FirstVC dans viewDidLoad, ce qui ne se produira pas tant que vous n'avez pas chargé la vue de metronomePlay instanciée dans SecondVC

Vous devez appeler _ = metronomePlay.view, ce qui chargera la vue de SecondVC et exécutera par la suite viewDidLoad avant d'appeler réellement metronomePlay.metronome.

0
bartlomiej.n

Vous initialisez metronome dans viewDidLoad méthode de FirstVC. Dans SecondVC, vous initialisez metronomePlay en tant que propriété stockée, mais vous ne demandez jamais à ViewController view et donc viewDidLoad sur FirstVC n'est pas appelé, ce qui a pour résultat que metronome (propriété stockée) n'est pas initialisé.

0
Puneet Sharma