尝试从外部模态视图控制器调用视图控制器函数时出现致命错误
Fatal error when attempting to call a view controller function from an external modal view controller
总结
我目前面临一个问题,在 Objective-C 中一直运行良好,但我似乎无法在 Swift(特别是 v3)中运行。这都是使用故事板构建的。我有两个独立的视图控制器:
- ViewController: WKWebView & UIButtonItems
- SideMenuTableView: UITableView 和 UIButtons
目前,SideMenu 以模态方式弹出到 ViewController 之上,并通过 UIButtons 列出一组操作。我想我会离开最简单的例子,只是为了把这个想法记下来。在此示例中,我试图完成的是从 UIButton tap (SideMenuTableView) 重新加载 WKWebView (ViewController)。如果事情仍然不清楚,下面是我试图得到的更清晰的图片:
目前,我可以使用简单的 Storyboard segue 调用 SideMenu (Kind: Present Modally)
。此外,我可以忽略实现为简单 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
}
}
}
您正在用 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
符合这个协议(在class里面必须要有刷新功能),才会执行刷新功能
总结
我目前面临一个问题,在 Objective-C 中一直运行良好,但我似乎无法在 Swift(特别是 v3)中运行。这都是使用故事板构建的。我有两个独立的视图控制器:
- ViewController: WKWebView & UIButtonItems
- SideMenuTableView: UITableView 和 UIButtons
目前,SideMenu 以模态方式弹出到 ViewController 之上,并通过 UIButtons 列出一组操作。我想我会离开最简单的例子,只是为了把这个想法记下来。在此示例中,我试图完成的是从 UIButton tap (SideMenuTableView) 重新加载 WKWebView (ViewController)。如果事情仍然不清楚,下面是我试图得到的更清晰的图片:
目前,我可以使用简单的 Storyboard segue 调用 SideMenu (Kind: Present Modally)
。此外,我可以忽略实现为简单 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
}
}
}
您正在用 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
符合这个协议(在class里面必须要有刷新功能),才会执行刷新功能