如何使用委托和协议快速编辑和传递单元格数据

时间:2018-12-30 10:27:46

标签: ios swift uitableview delegates protocols

我有两个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
    }

}

3 个答案:

答案 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)
}


}