我已经查看了Stackoverflow,但我无法得到答案。我想创建停止在另一个ViewController中播放声音的函数。但是当我点击停止按钮时,它会破解并显示" EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)"。这是我的代码。
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)
}
}
和另一个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)"
}
}
答案 0 :(得分:13)
您正在创建FirstVC的新副本,并在尚未初始化的内容上调用stop。
在这种情况下,您应该使用委托,例如
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)
}
因此,您将第一个VC传递给第二个VC,因此当您调用这些函数时,您正在使用正在使用的实际FirstVC上,而不是创建一个新函数。
如果您愿意,可以将var delegate: controlsAudio?
替换为var firstVC: FirstVC?
并指定,但我不建议
答案 1 :(得分:10)
从今天的swift 4.1开始,这段代码对我有用:
把它放在发送控制器中:
NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
把它放在接收控制器viewDidLoad()或viewWillAppear()中:
NotificationCenter.default.addObserver(self, selector: #selector(disconnectPaxiSocket(_:)), name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)
然后接收控制器类中的以下函数:
@objc func disconnectPaxiSocket(_ notification: Notification) {
ridesTimer.invalidate()
shared.disconnectSockets(socket: self.socket)
}
答案 2 :(得分:4)
迅速5:
将其放入操作
NotificationCenter.default.post(name: Notification.Name("NewFunctionName"), object: nil)
将其放在其他viewcontroller的viewdidload()中(您要使用的函数在哪里)
NotificationCenter.default.addObserver(self, selector: #selector(functionName), name: Notification.Name("NewFunctionName"), object: nil)
功能
@objc func functionName (notification: NSNotification){ //add stuff here}
我希望我能帮上忙
答案 3 :(得分:3)
我使用这种方式从另一个viewControllers调用函数:
let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);
答案 4 :(得分:2)
更新@Scriptable的答案 Swift 4
第1步:
在视图控制器中添加此代码,您可以从中按下按钮以停止声音。
@IBAction func btnStopSound(_ sender: AnyObject)
{
notificationCenter.post(name: Notification.Name("stopSoundNotification"), object: nil)
}
第2步:
现在是最后一步。现在将以下代码添加到结果视图控制器中,您希望自动停止声音。
func functionName (notification: NSNotification) {
metronomePlay.metronome.stop()
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "functionName",name:"stopSoundNotification", object: nil)
}
答案 5 :(得分:1)
var metronomePlay = FirstVC()
您正在FirstVC上创建一个新实例,而应该在已加载FirstVC的同一实例上执行该功能。
答案 6 :(得分:0)
您正在使用metronome
viewDidLoad
方法初始化FirstVC
。
在SecondVC
中,您将metronomePlay
初始化为存储属性,但从不要求ViewController的视图,因此viewDidLoad
的{{1}}未被调用,导致{{1} (存储的属性)没有初始化。
答案 7 :(得分:0)
您在metronome
的{{1}}上初始化FirstVC
,在viewDidLoad
加载metronomePlay
实例化视图之前,这不会发生。
在实际调用SecondVC
之前,您必须致电_ = metronomePlay.view
,它会懒惰地加载SecondVC
的视图并随后执行viewDidLoad
。
答案 8 :(得分:0)
使用通知进程从任何地方停止或使用SecondVC类中的相同FirstVC实例。
答案 9 :(得分:0)
您可以通过多种方式从其他viewController调用函数。
上面已经讨论的两种方法是通过委托人和协议以及通过发送通知。
另一种方法是将闭包从firstVC传递到第二个viewController。
以下是在代码中选择SecondVC时,我们传递一个闭包以停止节拍器的代码。 不会有问题,因为您传递的是相同的firstVC(而不是创建新实例),因此节拍器不会为零。
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
}
}
}
答案 10 :(得分:-1)
在SecondVC中尝试此操作。 var metronomePlay = FirstVC()。节拍器