尝试从外部模态视图控制器调用视图控制器函数时出现致命错误

Posted

技术标签:

【中文标题】尝试从外部模态视图控制器调用视图控制器函数时出现致命错误【英文标题】:Fatal error when attempting to call a view controller function from an external modal view controller 【发布时间】:2017-01-16 23:07:48 【问题描述】:

总结

我目前面临一个在 Objective-C 中一直运行良好的问题,但我似乎无法让它在 Swift(特别是 v3)中运行。这一切都是使用故事板构建的。我有两个独立的视图控制器:

    ViewController: WKWebView & UIButtonItems SideMenuTableView: UITableView 和 UIButtons

目前,SideMenu 以模态方式在 ViewController 顶部弹出,并通过 UIButtons 列出一组操作。我想我会离开最简单的例子,只是为了把这个想法记下来。在此示例中,我要完成的是从 UIButton 水龙头(SideMenuTableView)重新加载 WKWebView(ViewController)。如果事情仍然不清楚,下面是我想要了解的更清晰的图片:

目前,我可以使用简单的 Storyboard segue (Kind: Present Modally) 调用 SideMenu。此外,我可以关闭在一个简单的close() 函数中实现的 SideMenu。但是,在尝试调用刷新函数时,我收到以下错误消息:

fatal error: unexpectedly found nil while unwrapping an Optional value

代码

import UIKit
import WebKit

class ViewController: UIViewController, UINavigationControllerDelegate, WKNavigationDelegate 

    var webView: WKWebView!

    override func viewDidLoad() 
        super.viewDidLoad()

        let webURL = URL(string: "https://google.ca")
        let webRequest = URLRequest(url: webURL!)
        webView.load(webRequest)

    func refresh() 
        webView.reload()
    




import Foundation    

class SideMenuTableView: UITableViewController 

    @IBAction fileprivate func close() 
        self.dismiss(animated: true, completion: nil)
    

    @IBAction func refresh(sender: AnyObject!) 
        ViewController().refresh()
        close()
    

编辑:更新了 segue 代码。

// MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
        if let vc = segue.destination as? SideMenuTableView 
            vc.delegate = self
        
    

【问题讨论】:

What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?的可能重复 顺便说一句 ViewController().refresh() 没有任何意义。您正在初始化一个 new 视图控制器并在其上调用 refresh 谢谢@JAL!我想知道我到底在用那个代码做什么。 【参考方案1】:

您正在使用ViewController().refresh() 初始化一个新的UIViewController。委托模式是完成您正在尝试的事情的更好方法:

创建协议:

protocol MainViewControllerDelegate /* Can be called whatever you like */ 
    func refresh()

并让您的ViewController 符合它。

在您的SideMenuTableView 中创建一个变量来保存对其委托的引用。

weak var delegate: MainViewControllerDelegate? 

ViewController 的 prepareForSegue() 函数中。检查目标segue是否是您的SideMenuTableView

if let vc = destination.vc as? SideMenuTableView 
    vc.delegate = self

现在在你的@IBAction 按钮中点击 SideMenuTableView 调用委托方法。

@IBAction func refresh(sender: AnyObject!) 
        delegate?.refresh()
        close()

因为你的ViewController 符合这个协议(它的类中必须有一个刷新函数),所以会执行刷新函数。

【讨论】:

啊!这就是我正在寻找的解决方案!现在,从初学者的角度来看,我该去哪里实现协议,以及使其符合 ViewController?我是把它作为扩展类型的 sn-p 放在 ViewController 中,还是放在 AppDelegate 中? 我通常将我的协议放在我的类下面的同一个文件中,它是一个委托关闭。你可以通过在类名后面写下你的协议名来遵守它,就像你对其他代表所做的那样。然后创建一个与您在协议中描述的名称和参数相同但现在在您的类中的函数。 非常感谢!我一直想知道扩展、协议等的正确放置。 我还更新(添加了编辑)我的代码以找出最终问题。您能解释一下为什么我的代码不起作用以及您的代码到底在做什么吗?仍然试图抓住 ViewControllers 之间数据传递的整个过程。 我会推荐观看:youtube.com/watch?v=D-xXRSCLNFQ,它将解释一些基本概念。我认为视觉上的口头解释可能会有所帮助;)如果您在观看后仍有问题,请随时提问。

以上是关于尝试从外部模态视图控制器调用视图控制器函数时出现致命错误的主要内容,如果未能解决你的问题,请参考以下文章

从模态弹出到根视图控制器

视图控制器调用模态视图

如何从标签栏控制器弹出或模态显示视图控制器?

进行模态搜索时出现错误的 ViewController(使用 ECSlidingViewController)

从模态视图控制器调用方法

当模态视图控制器被解除时如何调用函数