我有两个VC,第一个是tableView,第二个是detailView VC,您可以在其中向tableView添加新项目。 我已经实现了通过segues(从第一个VC中的加号按钮)向前传递数据,并在向tableView添加新项时(通过在第二个VC上点击保存按钮触发)向后传递了委托和协议。
我将原型单元中的segue添加到第二个VC(详细视图),我还设法在第一个VC中测试触发了segue的情况,即:添加新项或转到该项的detailView。我面临的问题是,第二个VC中的“保存”按钮不再起作用(并且“取消”按钮也不再起作用),我希望能够编辑第二个VC中的文本字段,然后单击“保存”按钮以将编辑后的项目保存回来在第一个。 我找到了一种轻松解决问题的方法,但是我想知道如何使用委托吗?
我的第一个VC代码:
class ThingsTableViewController: UITableViewController, CanReceive {
var myThings = [Thing]()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myThings.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = myThings[indexPath.row].name
cell.detailTextLabel?.text = myThings[indexPath.row].type
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addNewThing" {
let secondVC = segue.destination as! UINavigationController
let ThingsViewController = secondVC.topViewController as! ThingsViewController
ThingsViewController.delegate = self
} else if segue.identifier == "showDetail" {
guard let thingDetailViewController = segue.destination as? ThingsViewController else {fatalError("Unknown Destination")}
guard let selectedCell = sender as? UITableViewCell else {
fatalError("Unexpected sender: \(sender)")
}
guard let indexPath = tableView.indexPath(for: selectedCell) else {
fatalError("The selected cell is not being displayed by the table")
}
let selectedThing = myThings[indexPath.row]
thingDetailViewController.thing = selectedThing
}
}
func dataReceived(data: Thing) {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
myThings[selectedIndexPath.row] = data
tableView.reloadRows(at: [selectedIndexPath], with: .none)
} else {
myThings.append(data)
tableView.reloadData()
}
}
第二个vc中的代码如下:
protocol CanReceive {
func dataReceived(data: Thing)
}
}
class ThingsViewController: UIViewController, UITextFieldDelegate {
var delegate : CanReceive?
var thing : Thing?
@IBOutlet weak var thingNameTextField: UITextField!
@IBOutlet weak var thingTypeTextfield: UITextField!
@IBAction func saveThingButton(_ sender: UIBarButtonItem) {
let newThing = Thing(name: thingNameTextField.text!, type: thingTypeTextfield.text!)
delegate?.dataReceived(data: newThing)
self.dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
@IBAction func cancelButton(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
thingNameTextField.delegate = self
updateSaveButtonState()
if let thing = thing {
navigationItem.title = thing.name
thingNameTextField.text = thing.name
thingTypeTextfield.text = thing.type
}
}
// MARK: UITextField Delegate
// get triggered when the user hit the return key on the keyboard
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
thingNameTextField.resignFirstResponder()
self.navigationItem.rightBarButtonItem?.isEnabled = true
return true
}
//gives chance to read info in text field and do something with it
func textFieldDidEndEditing(_ textField: UITextField) {
updateSaveButtonState()
navigationItem.title = thingNameTextField.text
}
func updateSaveButtonState() {
let text = thingNameTextField.text
self.navigationItem.rightBarButtonItem?.isEnabled = !text!.isEmpty
}
}
答案 0 :(得分:1)
在ThingsViewController
类中,请用weak var
定义委托
weak var delegate: CanReceive?
又发现了一个问题,
看起来您的实例名称和类名称相同,请更新实例名称,
if segue.identifier == "addNewThing" {
let secondVC = segue.destination as! UINavigationController
let thingsVC = secondVC.topViewController as! ThingsViewController
thingsVC.delegate = self
} else if segue.identifier == "showDetail" {
guard let thingDetailViewController = segue.destination as?
ThingsViewController else {fatalError("Unknown Destination")}
guard let selectedCell = sender as? UITableViewCell else {
fatalError("Unexpected sender: \(sender)")
}
guard let indexPath = tableView.indexPath(for: selectedCell) else {
fatalError("The selected cell is not being displayed by the table")
}
let selectedThing = myThings[indexPath.row]
thingDetailViewController.thing = selectedThing
thingDetailViewController.delegate = self
}
您的tableView.reloadData()
应该发生在main queue
func dataReceived(data: Thing) {
myThings.append(data)
DispatchQueue.main.async {
tableView.reloadData()
}
}
答案 1 :(得分:1)
您要设置delegate
的情况是segue的标识符为addNewThing
,但是标识符为showDetail
的情况又如何呢?
为segue的标识符为delegate
的情况设置segue的目的地showDetail
if segue.identifier == "addNewThing" {
...
} else if segue.identifier == "showDetail" {
...
thingDetailViewController.delegate = self
...
}
然后,当您需要关闭嵌入在导航控制器中的ViewController时,先将其关闭,然后再关闭导航控制器
答案 2 :(得分:0)
声明用于接收数据的协议。
protocol ViewControllerDelegate: class {
func didTapButton(with data: Int)
}
声明要在其中发送数据的协议的代表
class SecondVC: UIViewController {
weak var delegate: ViewControllerDelegate?
@IBAction func buttonPressed(_ sender: UIButton) {
delegate?.didTapButton(with: sender.tag)
}
}
确认要在何处接收数据的协议,并使委托成为self。
class FirstVC : UIViewController,ViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
func gotoSecond() {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "identifier") as! SecondVC
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true)
}
func didTapButton(with data: Int) {
print(data)
}
}