Функция вызова из другого 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(). метроном