หน้า Edit
หน้า edit เราจะใช้หน้าเดียวกันกับหน้า Add เลยเพราะมีอยู่แล้ว เพียงแค่เราเอาค่ามากรอกให้ก่อน แทนที่จะเป็นเปล่า ๆ
เริ่มต้นให้เราสร้าง Segue เพื่อแสดงหน้า Add อีกอันหนึ่ง แต่ทีนี้เราจะแยกเป็นอีก Segue นึง มี identifier เป็น openEditItemSegue
จากนั้นที่ AddNewItemViewController จะต้องเพิ่มตัวแปรที่ใช้เก็บ todo item ที่เราจะแก้ เพื่อเอามาใช้ในการกรอกค่าใน TextField และ Switch
Copy var todoItem: TodoItem ?
เมื่อหน้า Add ถูกโหลด เราก็ตรวจว่ามี todo item ที่ใช้แก้ไหม ถ้ามีเราก็ set ค่าใน TextField และ Switch พร้อมเปลี่ยนหัว Title เป็น Edit item หรือ Add new item ด้วย
Copy override func viewDidLoad () {
super. viewDidLoad ()
if let todoItem = todoItem {
title = "Edit item"
titleTextField. text = todoItem.title
isDoneSwitch. setOn ( todoItem.isDone, animated : true )
} else {
title = "Add new item"
}
}
จากนั้นเพื่อให้หน้าแรกรู้ว่าแก้เสร็จแล้วเหมือนตอน Add เราจะเพิ่มฟังก์ชั่นใน delegate
Copy func addNewItemViewController ( controller : AddNewItemViewController, didEdit item : TodoItem)
พอผู้ใช้กด Done เราก็ตรวจว่าตอนนี้เป็น Edit หรือ Add ถ้าเป็น Add เราก็สร้างของแล้วเรียก delegate Add กลับไป แต่ถ้าเป็น Edit เราก็ต้อง set ค่ากลับใน todo item ตามที่กรอกเข้ามา แล้วเรียก delegate Edit กลับไป
Copy @IBAction func doneButtonDidTap ( _ sender : UIBarButtonItem) {
if let title = titleTextField. text , ! title. isEmpty {
if let todoItem = todoItem {
todoItem.title = title
todoItem.isDone = isDoneSwitch.isOn
delegate ? . addNewItemViewController ( controller : self, didEdit : todoItem )
} else {
let todoItem = TodoItem ( title : title, isDone : isDoneSwitch.isOn )
delegate ? . addNewItemViewController ( controller : self, didAdd : todoItem )
}
}
}
if ซ้อน if ดูไม่ค่อยสวย เราเขียนให้เป็น Swifty ได้อีกหน่อย ด้วยการใช้ guard ถ้าเราไม่สามารถอ่านค่า title ได้ หรือ title เป็นค่าว่างเราก็จะไม่ทำอะไรต่อ Return ไปเลย
Copy @IBAction func doneButtonDidTap ( _ sender : UIBarButtonItem) {
guard let title = titleTextField. text , ! title. isEmpty else {
return
}
if let todoItem = todoItem {
todoItem.title = title
todoItem.isDone = isDoneSwitch.isOn
delegate ? . addNewItemViewController ( controller : self, didEdit : todoItem )
} else {
let todoItem = TodoItem ( title : title, isDone : isDoneSwitch.isOn )
delegate ? . addNewItemViewController ( controller : self, didAdd : todoItem )
}
}
กลับมาที่ ViewController เราต้องเพิ่ม delegate ฟังก์ชั่น Edit ที่เพิ่มขึ้นมา เพื่อ reload จอหน้าที่รายการนั้น
Copy func addNewItemViewController ( controller : AddNewItemViewController, didEdit item : TodoItem) {
if let index = todo. index ( of : item ) {
tableView ? . reloadRows ( at : [IndexPath ( row : index, section : 0 ) ], with : .automatic )
}
controller. dismiss ( animated : true , completion : nil )
}
เรายังขาดคนที่สั่งให้ Segue ทำงาน เพราะเราผูกจาก Controller ไปยังหน้า Edit ไม่ได้ผูกจากปุ่มแบบตอนกด Add เราจึงต้องสั่งเอง Manual ตอนที่เรากดที่ cell
เพิ่ม performSegue(withIdentifier:sender:) ที่ tableView(_:didSelectRowAt:) โดยเราจะส่ง todoItem ไปตอนสั่ง Segue ด้วย
Copy func tableView ( _ tableView : UITableView, didSelectRowAt indexPath : IndexPath) {
tableView. deselectRow ( at : indexPath, animated : true )
performSegue ( withIdentifier : "openEditItemSegue" , sender : todo.item ( at : indexPath.row ))
}
ทีนี้เราก็พร้อมละ แต่ครบแล้วหรือยัง ยังไม่ครบนะ เรายังไม่ได้ส่ง todo item ไปให้หน้า Edit เลย เราจะส่งผ่านไปตอนที่เรา prepare(for:sender:) ตามนี้
Copy override func prepare ( for segue : UIStoryboardSegue, sender : Any ? ) {
if segue.identifier == "openAddItemSegue" {
if let nav = segue.destination as? UINavigationController,
let controller = nav.topViewController as? AddNewItemViewController {
controller.delegate = self
}
} else if segue.identifier == "openEditItemSegue" {
if let nav = segue.destination as? UINavigationController,
let controller = nav.topViewController as? AddNewItemViewController {
controller.todoItem = sender as? TodoItem
controller.delegate = self
}
}
}
สุดท้ายลองปรับหน้าจอกันหน่อย ลองทำให้เป็นแบบนี้ดูสิว่าทำอย่างไร