快速从另一个 ViewController 调用函数
Posted
技术标签:
【中文标题】快速从另一个 ViewController 调用函数【英文标题】:Calling function from another ViewController in swift 【发布时间】:2017-02-09 11:23:47 【问题描述】:我已经查看了 ***,但我无法得到答案。我想创建停止在另一个 ViewController 中播放声音的功能。但是当我单击停止按钮时,它破裂并显示“EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)”。这是我的代码。
第一个视图控制器
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】:从今天的 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)
【讨论】:
【参考方案2】:斯威夫特 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
希望对你有帮助
【讨论】:
【参考方案3】:您正在创建 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 传递给第二个 VC,因此当您调用这些函数时,您是在正在使用的实际 FirstVC 上执行此操作,而不是创建一个新的。
如果你愿意的话,你可以不用协议来做到这一点,方法是将 var delegate: controlsAudio?
替换为 var firstVC: FirstVC?
并分配它,但我不推荐它
【讨论】:
协议对我不起作用,因为 SecondVC 中的委托为零 它看起来对 19 个人赞成答案有效。你在使用弱引用吗?您是否正确设置了委托并持有对 VC 的引用? @Marcel,我遇到了同样的问题。我不使用情节提要,因此需要在 SecondVC 中明确声明self.delegate = FirstVC()
,并且主要在 viewDidLoad
方法中声明。这解决了我的问题,否则你会得到 nil,因为委托属性永远不会被赋值。【参考方案4】:
我使用这种方式从另一个 viewControllers 调用我的函数:
let sendValue = SecondViewController();
sendValue.YourFuncion(data: yourdata);
【讨论】:
【参考方案5】:您可以通过多种方式从其他 viewController 调用函数。
上面已经讨论过的两种方式是委托和协议以及发送通知。
另一种方法是从 firstVC 将闭包传递给您的第二个 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
【讨论】:
伙计,你救了我许多不遗余力的事!非常感谢!【参考方案6】:var metronomePlay = FirstVC()
您正在 FirstVC 上创建一个新实例,而应该在已加载的 FirstVC 的同一实例上执行该功能。
【讨论】:
【参考方案7】:更新@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)
【讨论】:
注意:从技术上讲,这不是我转换为 Swift 4 的答案。我的答案使用了所有 Swift 版本中使用的委托模式。这只是 Swift 4 中的一种不同方式。【参考方案8】:您正在FirstVC
的viewDidLoad
方法中初始化metronome
。
在SecondVC
中,您将metronomePlay
初始化为存储属性,但从不询问ViewController 的视图,因此FirstVC
的viewDidLoad
没有被调用,这导致metronome
(存储属性)没有被初始化。
【讨论】:
【参考方案9】:您在viewDidLoad
中的FirstVC
上初始化metronome
,直到您加载在SecondVC
中实例化的metronomePlay
的视图时才会发生这种情况。
你必须调用_ = metronomePlay.view
,它会延迟加载SecondVC
的视图并随后执行viewDidLoad
,然后才真正调用metronomePlay.metronome
。
【讨论】:
【参考方案10】:在 SecondVC 中试试这个。 var metronomePlay = FirstVC().metronome
【讨论】:
这将访问一个新实例,而不是当前正在播放的当前实例。【参考方案11】:要么使用通知进程从任何地方停止,要么使用 SecondVC 类中的相同 FirstVC 实例。
【讨论】:
你能分享一些你所说的过程的sn-p吗?以上是关于快速从另一个 ViewController 调用函数的主要内容,如果未能解决你的问题,请参考以下文章
从另一个 ViewController 调用一个 ViewController 的实例方法
需要从另一个viewController调用其他viewController中的方法
从另一个 .swift 文件调用 ViewController 函数