2017-02-09 3 views
6

Я уже посмотрел в Stackoverflow, но я не могу получить ответ. Я хочу создать функцию, которая перестает воспроизводить звук в другом ViewController. Но когда я нажал кнопку остановки, он взломал и показал «EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, subcode = 0x0)». Это мой код.Функция вызова из другого ViewController в swift

Первого 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

Вы можете использовать Центр уведомлений, отправив уведомление на контроллер второго вида. Я думаю, это поможет вам –

ответ

0

Вы инициализация metronome в viewDidLoad методе FirstVC. В SecondVC вы инициализируете metronomePlay как запомненное свойство, но никогда не запрашиваете вид ViewController, и поэтому viewDidLoad из FirstVC не получает вызов, который приводит к тому, что результаты metronome (хранимое свойство) не инициализируются.

0
var metronomePlay = FirstVC() 

вы создаете новый экземпляр на FirstVC, вместо этого вы должны выполнять функции в одном экземпляре, который уже загружен FirstVC.

3

Вы создаете новую копию 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? и назначение, но я бы не рекомендовал его

-1

Попробуйте это в SecondVC. var metronomePlay = FirstVC(). metronome

+0

, который будет обращаться к новому экземпляру, а не к текущему экземпляру, который в данный момент воспроизводится. – Scriptable

8

Если вы хотите нажать кнопку из 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) 
} 

Теперь реализовать этот код-вещи в вашем коде. Надеюсь, это сработает для вас.

+0

Даже вы можете сослаться на этот ответ: http://stackoverflow.com/a/39366688/5886755 –

+0

Спасибо! Синтаксис этого немного изменился с помощью Swift 3: NotificationCenter.default.addObserver (self, selector: #selector (self.refresh), имя: NSNotification.Name (rawValue: "refreshData"), object: nil) – Nate23VT

0

Вы инициализировать metronome на FirstVC в viewDidLoad, что не будет происходить до тех пор, пока не будет загружено мнение metronomePlay инстанцированного в SecondVC. Вы должны позвонить _ = metronomePlay.view сначала по телефону SecondVC, прежде чем на самом деле позвонить metronomePlay.metronome.

-1

Обновление @ ответ 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) 

    } 
Смежные вопросы