ios 快速从另一个 ViewController 调用函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42135402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:52:08  来源:igfitidea点击:

Calling function from another ViewController in swift

iosswiftavplayer

提问by Andyopf

I have already looked in Stackoverflow but I can't get an answer. I want to create function that stop playing the sound in another ViewController. But when I clicked the stop button, it cracked and showed "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)". This is my code.

我已经查看了 Stackoverflow,但我无法得到答案。我想创建停止在另一个 ViewController 中播放声音的函数。但是当我单击停止按钮时,它破裂并显示“EXC_BAD_INSTRUCTION (code=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)
    }
}

and another Viewcontroller is

另一个视图控制器是

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)"
   }
}

回答by shanezzar

As of swift 4.1 today, this code worked for me:

从今天的 swift 4.1 开始,这段代码对我有用:

Put this in sending controller:

把它放在发送控制器中:

NotificationCenter.default.post(name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)

Put this in receiving controller viewDidLoad() or viewWillAppear():

把它放在接收控制器 viewDidLoad() 或 viewWillAppear() 中:

NotificationCenter.default.addObserver(self, selector: #selector(disconnectPaxiSocket(_:)), name: Notification.Name(rawValue: "disconnectPaxiSockets"), object: nil)

and then the following function in your receiving controller class:

然后在您的接收控制器类中使用以下函数:

@objc func disconnectPaxiSocket(_ notification: Notification) {
    ridesTimer.invalidate()
    shared.disconnectSockets(socket: self.socket)
}

回答by Scriptable

You are creating a NEW copy of FirstVC and calling stop on something that is not yet initialised.

您正在创建 FirstVC 的新副本,并对尚未初始化的内容调用 stop。

You should really use a delegate in this case, something like

在这种情况下,您真的应该使用委托,例如

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)

}

So you are passing first VC to the second VC, so when you call these functions you are doing it on the actual FirstVC that is in use, rather than creating a new one.

因此,您将第一个 VC 传递给第二个 VC,因此当您调用这些函数时,您是在正在使用的实际 FirstVC 上执行此操作,而不是创建一个新的。

You could do this without protocols if you like by replacing the var delegate: controlsAudio?with var firstVC: FirstVC?and assigning that, but I wouldn't recommend it

如果你愿意,你可以在没有协议的情况下通过替换var delegate: controlsAudio?withvar firstVC: FirstVC?并分配它来做到这一点,但我不推荐它

回答by Romy

Swift 5:

斯威夫特 5:

Put this in the Action

把这个放在行动中

NotificationCenter.default.post(name: Notification.Name("NewFunctionName"), object: nil)

Put this in viewdidload() in a different viewcontroller (where is the function you want to use)

把它放在不同的视图控制器中的 viewdidload() 中(你要使用的函数在哪里)

NotificationCenter.default.addObserver(self, selector: #selector(functionName), name: Notification.Name("NewFunctionName"), object: nil)

The function

功能

 @objc func functionName (notification: NSNotification){ //add stuff here}

I hope I was helpful

我希望我有帮助

回答by Minas Petterson

I use this way to call my functions from another viewControllers:

我使用这种方式从另一个 viewController 调用我的函数:

let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);

回答by Alex Bailey

Updating @Scriptable's answer for Swift 4

更新 @Scriptable 对Swift 4的回答

Step 1 :

第1步 :

Add this code in your view controller, from which you want to press button click to stop sound.

将此代码添加到您的视图控制器中,您希望从中按下按钮单击以停止声音。

@IBAction func btnStopSound(_ sender: AnyObject)
{
    notificationCenter.post(name: Notification.Name("stopSoundNotification"), object: nil)

}

Step 2:

第2步:

Now its final step. Now add this below code, to your result view controller, where you want to automatically stop sound.

现在是最后一步。现在将下面的代码添加到您的结果视图控制器中,您希望在其中自动停止声音。

func functionName (notification: NSNotification) {
           metronomePlay.metronome.stop()
}

override func viewWillAppear(animated: Bool) {
           NSNotificationCenter.defaultCenter().addObserver(self, selector: "functionName",name:"stopSoundNotification", object: nil)

}

回答by Emel Elias

var metronomePlay = FirstVC()

you are creating a new instance on FirstVC, instead you should perform the function on the same instance that of already loaded FirstVC.

您正在 FirstVC 上创建一个新实例,而应该在已加载的 FirstVC 的同一实例上执行该功能。

回答by Amyth

You can call function from other viewControllers in many ways.

您可以通过多种方式从其他视图控制器调用函数。

Two ways that are already discussed above are by delegates & protocols and by sending notifications.

上面已经讨论过的两种方式是通过委托和协议以及通过发送通知。

Another way is by passing closures to your second viewController from firstVC.

另一种方法是将闭包从 firstVC 传递给您的第二个 viewController。

Below is the code in which while segueing to SecondVC we pass a closure to stop the metronome. There will be no issue because you are passing the same firstVC (not creating a new instance), so the metronome will not be nil.

下面是在转入 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
      }

   }

 }

回答by bartlomiej.n

You initialize metronomeon FirstVCin viewDidLoad, which won't happen until you load the view of metronomePlayinstantiated in SecondVC.

metronomeFirstVCin上进行初始化,在viewDidLoad您加载metronomePlayin 实例化视图之前不会发生这种情况SecondVC

You have to call _ = metronomePlay.view, which will lazily load the view of SecondVCand subsequently execute viewDidLoad, before actually calling metronomePlay.metronome.

在实际调用之前_ = metronomePlay.view,您必须调用,这将延迟加载 的视图SecondVC并随后执行。viewDidLoadmetronomePlay.metronome

回答by Puneet Sharma

You are initialising metronomein viewDidLoadmethod of FirstVC. In SecondVC, you are initialising metronomePlayas a stored property, but never asking for ViewController's view and thus viewDidLoadof FirstVCis not getting called which results in metronome(stored property) not getting initialised.

您正在使用metronomeviewDidLoad方法进行初始化FirstVC。在 中SecondVC,您正在初始化metronomePlay为存储属性,但从不请求 ViewController 的视图,因此viewDidLoadofFirstVC不会被调用,这导致metronome(存储属性)未初始化。

回答by guestme

Try this in SecondVC. var metronomePlay = FirstVC().metronome

在 SecondVC 中试试这个。var 节拍器播放 = FirstVC().节拍器