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

标签 ios delegation

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

问题:相同的 UITableView 应该出现在两个不同的位置(SignUpViewControllerSettingsViewController)。此外,SignUpViewControllerSettingsViewController 应该了解帐户验证的成功或失败。

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

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

最佳答案

为什么双重授权是个问题?据我所知,您有 2 个 TableView ,每个 Controller 1 个。然后每个 Controller 将每个 TableView 的委托(delegate)设置为自己。即使不是,在运行时更改对象的委托(delegate)也很常见。具有相同协议(protocol)的 2 个委托(delegate)属性也很正常,只是为了能够将消息转发给 2 个或更多对象。

还有很多选择。您可以使用默认的通知中心,并能够通过这种方式转发消息。唯一的坏处是您需要从通知中心显式退出通知监听器。

在您的案例中,另一个更有趣的过程是创建一个模型(一个类),它保存来自 TableView 的数据并实现来自单元格的协议(protocol)。然后模型应该作为属性转发给新的 View Controller 。如果 View Controller 仍然需要在 TableView 之外进行刷新,那么模型应该为 View Controller 本身包含另一个协议(protocol)。

以这样的事情为例:

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 个 View Controller 将与同一个对象通信,该对象也实现了 TableView 协议(protocol)。我不建议你把所有这些都放在一个文件中,但正如你所看到的,两个 View Controller 都非常干净,模型接管了所有繁重的工作。该模型可能有另一个委托(delegate),然后由 View Controller 本身使用它来转发其他信息。当 View 确实出现时, Controller 应该从模型中“窃取”委托(delegate)槽。

我希望这可以帮助您了解委托(delegate)并不是一维的,可以用它们做很多事情。

关于ios - iOS 中这种情况的最佳设计解决方案是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34413453/

相关文章:

ios - 当我在 xcode 5 中打开我的 xcode 4.5 项目时收到警告

iphone - 创建 plist 时的未知行为

swift - 从单元格委托(delegate)中删除重复代码代码

objective-c - 了解自定义委托(delegate)

ios - Aviary SDK 问题导致 ios 中的应用程序崩溃

ios - 在 xcode/swift 3 中点击一个 View 到 'select' 它

iphone - 当imagePicker出现时,iOS动画textView返回到原始位置?

ruby - 奇怪的 SimpleDelegator 行为

Kotlin 透明属性解析器?

jquery - Google Closure 事件委托(delegate) a'la jQuery live/on