私はすでにStackoverflowを調べましたが、答えが得られません。別のViewControllerでサウンドの再生を停止する関数を作成します。しかし、停止ボタンをクリックすると、割れて「EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP、subcode = 0x0)」と表示されました。これは私のコードです。
最初の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)"
}
}
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=を2番目のVCに渡すので、これらの関数を呼び出すときは、新しい関数を作成するのではなく、使用中の実際のFirstVCで実行します。
必要に応じて、プロトコルなしでこれを行うことができます。var delegate: controlsAudio?
with var firstVC: FirstVC?
そしてそれを割り当てるが、私はそれをお勧めしません
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)
}
この方法を使用して、別のviewControllersから関数を呼び出します。
let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);
Swift 4の@Scriptableの回答を更新する
ステップ1:
このコードをView Controllerに追加し、そこからボタンクリックを押してサウンドを停止します。
@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)
}
var metronomePlay = FirstVC()
firstVCで新しいインスタンスを作成する代わりに、既にロードされているFirstVCと同じインスタンスで機能を実行する必要があります。
他のviewControllersからさまざまな方法で関数を呼び出すことができます。
上記で既に説明した2つの方法は、デリゲートとプロトコルによるものと、通知の送信によるものです。
別の方法は、firstVCから2番目の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
}
}
}
通知プロセスを使用してどこからでも停止するか、SecondVCクラスの同じFirstVCインスタンスを使用します。
スイフト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}
お役に立てば幸いです
metronome
のFirstVC
でviewDidLoad
を初期化します。これは、metronomePlay
でインスタンス化されたSecondVC
のビューをロードするまで発生しません。
_ = metronomePlay.view
を呼び出す必要があります。これは、実際にmetronomePlay.metronome
を呼び出す前に、SecondVC
のビューを遅延ロードしてからviewDidLoad
を実行します。
metronome
のviewDidLoad
メソッドでFirstVC
を初期化しています。 SecondVC
では、metronomePlay
を保存プロパティとして初期化していますが、ViewControllerのビューを要求することはないため、viewDidLoad
のFirstVC
が呼び出されず、 metronome
(格納プロパティ)が初期化されていません。