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()。节拍器