iOS中这种情况的最佳设计解决方案是什么?

时间:2015-12-22 10:19:45

标签: ios delegation

我有两个静态单元格UITableView。当我在单元格中填充文本字段时,每个单元格都有自定义类并独立验证帐户名称。 (这部分代码我按原样获得,我不允许重写它)。如果委托(SocialFeedSelectCellDelegate)验证正确,则单元格会委派更改。最初,此tableView仅出现在SignUpViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, SocialFeedSelectCellDelegate中。

问题:相同的UITableView应出现在两个不同的地方(SignUpViewControllerSettingsViewController)。 SignUpViewControllerSettingsViewController也应了解帐户验证的成功与否。

我尝试了什么:我为tableView创建了SocialFeedTableViewController: UITableViewController, SocialFeedSelectCellDelegate,其中包含两个单元格。将SocialFeedTableViewController中的视图设置为SignUpViewControllerSettingsViewController的容器视图。我使用了第二个委托(从SocialFeedTVC到SignUp和Settings)来通知SignUp和Settings有关验证更改的信息。我认为这是个坏主意,因为双重授权。队友说我很难理解。

问题:问题的最佳和最简单的设计解决方案是什么?enter image description here

1 个答案:

答案 0 :(得分:1)

为什么双重授权是个问题?据我所知,你有2个表视图,每个控制器1个。然后每个控制器将每个表视图的委托设置为self。即使不是,在运行时更改对象的委托也很常见。拥有相同协议的2个委托属性也是正常的,只是为了能够将消息转发到2个或更多对象。

还有很多选择。您可以使用默认通知中心,并能够以这种方式转发邮件。唯一不好的是你需要从通知中心明确地重新通知通知监听器。

在您的情况下,另一个更有趣的过程是创建一个模型(一个类),它保存表视图中的数据,并从单元格实现协议。然后,该模型应作为属性转发到新的视图控制器。如果视图控制器仍需要刷新超出表视图,那么模型应该包含视图控制器本身的另一个协议。

举例来说:

protocol ModelProtocol: NSObjectProtocol {
    func cellDidUpdateText(cell: DelegateSystem.Model.MyCell, text: String?)
}

class DelegateSystem {
    class Model: NSObject, UITableViewDelegate, UITableViewDataSource, ModelProtocol {

        // My custom cell class
        class MyCell: UITableViewCell {
            weak var modelDelegate: ModelProtocol?
            var indexPath: NSIndexPath?

            func onTextChanged(field: UITextField) { // just an example
                modelDelegate?.cellDidUpdateText(self, text: field.text) // call the cell delegate
            }
        }

        // some model values
        var firstTextInput: String?
        var secondTextInput: String?

        // a delegate method from a custom protocol
        func cellDidUpdateText(cell: DelegateSystem.Model.MyCell, text: String?) {
            // update the appropriate text
            if cell.indexPath?.row == 0 {
                self.firstTextInput = text
            } else {
                self.secondTextInput = text
            }
        }

        // table view data source
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 2
        }
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = MyCell() // create custom cell
            cell.indexPath = indexPath // We want to keep track of the cell index path
            // assign from appropriate text
            if cell.indexPath?.row == 0 {
                cell.textLabel?.text = self.firstTextInput
            } else {
                cell.textLabel?.text = self.secondTextInput
            }
            cell.modelDelegate = self // set the delegate
            return cell
        }
    }

    // The first view controller class
    class FirstViewController: UIViewController {
        var tableView: UITableView? // most likely from storyboard
        let model = Model() // generate the new model

        override func viewDidLoad() {
            super.viewDidLoad()
            refresh() // refresh when first loaded
        }
        override func viewDidAppear(animated: Bool) {
            super.viewDidAppear(animated)
            refresh() // Refresh each time the view appears. This will include when second view controller is popped
        }

        func refresh() {
            if let tableView = self.tableView {
                tableView.delegate = model // use the model as a delegate
                tableView.dataSource = model // use the model as a data source
                tableView.reloadData() // refresh the view
            }
        }

        // probably from some button or keyboard done pressed
        func presentSecondController() {
            let controller = SecondViewController() // create the controller
            controller.model = model // assign the same model
            self.navigationController?.pushViewController(controller, animated: true) // push it
        }
    }

    // The second view controller class
    class SecondViewController: UIViewController {
        var tableView: UITableView? // most likely from storyboard
        var model: Model? // the model assigned from the previous view controller

        override func viewDidLoad() {
            super.viewDidLoad()
            refresh() // refresh when first loaded
        }
        override func viewDidAppear(animated: Bool) {
            super.viewDidAppear(animated)
            refresh() // Refresh each time the view appears. This will include when third view controller is popped
        }

        func refresh() {
            if let tableView = self.tableView {
                tableView.delegate = model // use the model as a delegate
                tableView.dataSource = model // use the model as a data source
                tableView.reloadData() // refresh the view
            }
        }

        // from back button for instance
        func goBack() {
            self.navigationController?.popViewControllerAnimated(true)
        }
    }
}

这里,2个视图控制器将与同一个对象进行通信,该对象也实现了表视图协议。我建议你不要将所有这些放在一个文件中,但正如你所看到的那样,两个视图控制器都非常干净,模型可以完成所有繁重的工作。该模型可以具有另一个委托,然后由视图控制器本身使用它来转发附加信息。然后控制器应该“偷”"视图确实出现时模型中的委托槽。

我希望这可以帮助你理解代表不是那么一维,可以用它们做很多事情。