在swift中从另一个ViewController调用函数

时间:2021-10-19 06:49:30

I have already looked in * 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.

我已经查看了*但我无法得到答案。我想创建停止在另一个ViewController中播放声音的函数。但是当我点击停止按钮时,它会破解并显示“EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP,subcode = 0x0)”。这是我的代码。

First ViewController

第一个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

另一个Viewcontroller是

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

9 个解决方案

#1


7  

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

您正在创建FirstVC的新副本,并在尚未初始化的内容上调用stop。

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.

因此,您将第一个VC传递给第二个VC,因此当您调用这些函数时,您将在正在使用的实际FirstVC上执行此操作,而不是创建新的。

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

如果您愿意,可以通过替换var delegate:controlsAudio来执行此操作。 with var firstVC:FirstVC?并指定,但我不会推荐它

#2


2  

Updating @Scriptable's answer for Swift 4

更新@Scriptable的Swift 4答案

Step 1 :

步骤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:

第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


1  

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

从今天的swift 4.1开始,这段代码对我有用:

Put this in sending controller:

把它放在发送控制器:

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

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

把它放在接收控制器的viewDidLoad()或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)
}

#4


0  

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.

您正在使用FirstVC的viewDidLoad方法初始化节拍器。在SecondVC中,您将metronomePlay初始化为存储属性,但从不要求ViewController的视图,因此未调用FirstVC的viewDidLoad会导致节拍器(存储属性)未初始化。

#5


0  

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.

您正在FirstVC上创建一个新实例,而应该在已加载FirstVC的同一实例上执行该功能。

#6


0  

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

使用通知进程从任何地方停止或使用SecondVC类中的相同FirstVC实例。

#7


0  

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

您在viewDidLoad中初始化FirstVC上的节拍器,直到您加载在SecondVC中实例化的metronomePlay视图才会发生。

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

您必须调用_ = metronomePlay.view,在实际调用metronomePlay.metronome之前,它将懒惰地加载SecondVC的视图并随后执行viewDidLoad。

#8


0  

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

我用这种方式从另一个viewControllers调用我的函数:

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

#9


-1  

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

在SecondVC中尝试这个。 var metronomePlay = FirstVC()。节拍器

#1


7  

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

您正在创建FirstVC的新副本,并在尚未初始化的内容上调用stop。

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.

因此,您将第一个VC传递给第二个VC,因此当您调用这些函数时,您将在正在使用的实际FirstVC上执行此操作,而不是创建新的。

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

如果您愿意,可以通过替换var delegate:controlsAudio来执行此操作。 with var firstVC:FirstVC?并指定,但我不会推荐它

#2


2  

Updating @Scriptable's answer for Swift 4

更新@Scriptable的Swift 4答案

Step 1 :

步骤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:

第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


1  

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

从今天的swift 4.1开始,这段代码对我有用:

Put this in sending controller:

把它放在发送控制器:

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

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

把它放在接收控制器的viewDidLoad()或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)
}

#4


0  

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.

您正在使用FirstVC的viewDidLoad方法初始化节拍器。在SecondVC中,您将metronomePlay初始化为存储属性,但从不要求ViewController的视图,因此未调用FirstVC的viewDidLoad会导致节拍器(存储属性)未初始化。

#5


0  

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.

您正在FirstVC上创建一个新实例,而应该在已加载FirstVC的同一实例上执行该功能。

#6


0  

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

使用通知进程从任何地方停止或使用SecondVC类中的相同FirstVC实例。

#7


0  

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

您在viewDidLoad中初始化FirstVC上的节拍器,直到您加载在SecondVC中实例化的metronomePlay视图才会发生。

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

您必须调用_ = metronomePlay.view,在实际调用metronomePlay.metronome之前,它将懒惰地加载SecondVC的视图并随后执行viewDidLoad。

#8


0  

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

我用这种方式从另一个viewControllers调用我的函数:

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

#9


-1  

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

在SecondVC中尝试这个。 var metronomePlay = FirstVC()。节拍器