ios - 为什么在我的代码中隐式解包 Optional 值时意外发现 nil?
问题描述
当我尝试使用另一个视图控制器将新任务保存在待办事项列表中时,我得到一个 Unexpectedly found nil ,同时在我的代码错误中隐式解包 Optional 值。当我点击一个按钮时,我打开了输入页面,然后有一个文本字段,我可以在其中输入文本以创建任务项。这是主视图控制器的代码:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
@IBOutlet var tableView: UITableView!
private var tasks = [TaskItem]()
override func viewDidLoad() {
super.viewDidLoad()
getAllTasks()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = tasks[indexPath.row].title
return cell
}
@IBAction func didTapNewTask(){
let viewContoller = storyboard?.instantiateViewController(identifier: "entry") as! EntryViewController
viewContoller.title = "New Task"
viewContoller.update = {
DispatchQueue.main.async {
self.getAllTasks()
}
}
navigationController?.pushViewController(viewContoller, animated: true)
}
//Core Data Functions
//Used to get all our tasks in our Core Data
func getAllTasks() {
do {
tasks = try context.fetch(TaskItem.fetchRequest())
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
catch {
print("error getting all tasks \(error)")
}
}
//This is used to create a task, setting the properties to those in the parameters and then saving to our Core Data.
func createTask(title: String, notes: String, difficulty: Int32) {
let task = TaskItem(context: context)
task.title = title
task.notes = notes
task.difficulty = difficulty
task.dateCreated = Date()
do {
try context.save()
getAllTasks()
}
catch {
}
}
这是入口视图控制器的代码:
class EntryViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var field: UITextField!
var update: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
field.delegate = self
// Do any additional setup after loading the view.
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
saveTask()
return true
}
@IBAction func saveTask(){
let vc = storyboard?.instantiateViewController(identifier: "tasks") as! ViewController
guard let text = field.text, !text.isEmpty else {
let alert = UIAlertController(title: "Error", message: "Please input a title" , preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Confirm", style: UIAlertAction.Style.default, handler: nil))
self.present(alert,animated: true,completion: nil)
return
}
vc.createTask(title: text, notes: "Hello", difficulty: 10)
update?()
navigationController?.popViewController(animated: true)
}
一旦我点击保存新任务,应用程序就会崩溃,但是一旦我重新加载应用程序,我刚刚创建的任务就在那里。
解决方案
@IBAction func saveTask(){
let vc = storyboard?.instantiateViewController(identifier: "tasks") as! ViewController
guard let text = field.text, !text.isEmpty else {
let alert = UIAlertController(title: "Error", message: "Please input a title" , preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Confirm", style: UIAlertAction.Style.default, handler: nil))
self.present(alert,animated: true,completion: nil)
return
}
vc.createTask(title: text, notes: "Hello", difficulty: 10)
update?()
navigationController?.popViewController(animated: true)
}
此方法的第一行是您的问题的根源。您在这里所做的是创建原始视图控制器的新实例,而不是您最初来自的实例。
这种工作暂时有效,因为您随后调用createTask
该视图控制器来执行您的新任务。这很好,但是该方法然后调用getAllTasks
,然后调度到主队列,然后调用重新加载表上的数据。
但是您的表不存在,因为这是视图控制器的一个新实例,它从未加载过它的视图。表格视图是一个隐式展开的可选项,但是当你在这里点击它时它是 nil。
您最好的解决方案是传入一个块(就像您使用更新一样)来创建一个新任务,并在该块中调用原始视图控制器上的方法。
推荐阅读
- powershell - 哈希表的 Powershell 数组
- python - 无法使用基于类的视图在 django 模板中返回值
- java - 在 Spring MVC 中结合 @ModelAttribute 和 @RequestBody 的功能
- java - 添加双向链表后如何移动元素
- javascript - 如何在javascript中用ID替换名称
- excel - 将用户窗体(进度条)置于一切之上
- r - 传单地图中的数据集和值之间的数据不匹配
- html - HTML将图像保持在行内而不会溢出
- swift - 如何在 Swift 5 中为多种类型进行扩展
- sql - Oracle Toad SQL 查询导致 id 计数不一致