Функция вызова из другого ViewController в быстром режиме
Я уже смотрел в Stackoverflow, но я не могу получить ответ. Я хочу создать функцию, которая перестает воспроизводить звук в другом ViewController. Но когда я нажал кнопку остановки, он взломал и показал "EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, subcode = 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)"
}
}
Ответы
Ответ 1
Вы создаете новую копию FirstVC и вызываете стоп на том, что еще не инициализировано.
В этом случае вы действительно должны использовать делегат, что-то вроде
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?
и назначив это, но я бы не рекомендовал его
Ответ 2
Если вы хотите нажимать кнопку из one_view_controller и останавливать звук на другом контроллере просмотра, выполните следующие действия.
Выполните следующие шаги:
Шаг 1:
Добавьте этот код в свой контроллер, из которого вы хотите нажать кнопку, чтобы остановить звук.
@IBAction func btnStopSound(_ sender: AnyObject)
{
NSNotificationCenter.defaultCenter().postNotificationName("stopSoundNotification", object: nil)
}
Версия Swift 4:
@IBAction func btnStopSound(_ sender: AnyObject)
{
NotificationCenter.default.post(name: Notification.Name(rawValue: "setTimerValue"), object: nil)
}
Шаг 2:
Теперь его последний шаг. Теперь добавьте этот ниже код в контроллер результатов, где вы хотите автоматически остановить звук.
func loadList(notification: NSNotification){
metronomePlay.metronome.stop()
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadList:",name:"stopSoundNotification", object: nil)
}
Версия Swift 4:
func loadList(notification: Notification){
metronomePlay.metronome.stop()
}
override func viewWillAppear(animated: Bool) {
NotificationCenter.default.addObserver(self, selector: Selector(("loadList:")), name: Notification.Name(rawValue: "stopSoundNotification"), object: nil)
}
Теперь реализуйте этот код в своей кодировке. Надеюсь, это сработает для вас.
Ответ 3
Начиная с 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)
}
Ответ 4
Обновление ответа @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
Вы инициализируете metronome
в viewDidLoad
методе FirstVC
.
В SecondVC
вы инициализируете metronomePlay
как хранимое свойство, но никогда не запрашиваете представление ViewController и, следовательно, viewDidLoad
of FirstVC
не получает вызов, результаты которого в metronome
(хранимое свойство) не получают инициализацию.
Ответ 6
var metronomePlay = FirstVC()
вы создаете новый экземпляр на FirstVC, вместо этого вы должны выполнить функцию в том же экземпляре, что и уже загруженный FirstVC.
Ответ 7
Вы инициализировать metronome
на FirstVC
в viewDidLoad
, что не будет происходить до тех пор, пока не будет загружено мнение metronomePlay
инстанцированного в SecondVC
.
Вы должны вызвать _ = metronomePlay.view
, который лениво загрузит представление SecondVC
и впоследствии выполнит viewDidLoad
, прежде чем фактически вызвать metronomePlay.metronome
.
Ответ 8
Либо использовать процесс уведомления для остановки из любого места, либо использовать тот же экземпляр FirstVC из класса SecondVC.
Ответ 9
Я использую этот способ для вызова своих функций из другого viewControllers:
let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);
Ответ 10
Попробуйте это в SecondVC. var metronomePlay = FirstVC(). метроном