【问题标题】:Delegation Among Container View Controllers容器视图控制器之间的委派
【发布时间】:2018-10-29 09:50:37
【问题描述】:

我有一个父视图控制器托管 3 个容器视图控制器。

在某些时候,我需要将数据从一个容器视图控制器传递到另一个容器视图控制器,并认为我可以通过委托模式来实现这一点。但是,我似乎无法弄清楚为什么没有触发委托并且接收容器视图控制器没有收到任何数据。

似乎无法发现我的设置方式可能存在什么问题。如果有推荐的方法在容器之间传递数据,我也全神贯注!

以下是设置的代码摘要:

class ParentViewController: UIViewController { 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let firstContainerVC = segue.destination as? FirstContainerVC {
            //....
        }

        if let secondContainerVC = segue.destination as? SecondContainerVC {
           //....
        }        
    }
        protocol Delegate {
           func passX(a: String?)
           func passY(b: String?)
        }
}    

class FirstContainerVC: UIViewController {

    var delegate: Delegate?

    if isTrue {
        delegate.passX(a: "TestOne")
    } else {
        delegate.passY(b: "TestTwo")
    }
}

class SecondContainerVC: UIViewController, Delegate {

    override func viewDidLoad() {
        let firstVC = self.storyboard?.instantiateViewController(withIdentifier: "firstContainer") as! FirstContainerVC
    firstVC.delegate = self
    }

    func passX(a: String?) {
        //if let a = a....
    }

    func passY(b: String?) {
        //if let b = b....
    }
}

【问题讨论】:

  • 如果第二个容器视图控制器都包含在同一个父视图控制器中,为什么还要实例化第一个容器视图控制器?
  • @slickdaddy 我想我必须实例化它来获取委托属性,抱歉我对此很陌生,你介意详细说明建议的方式吗?
  • 发布你的父视图控制器,我会解释。
  • @slickdaddy 重新发布,不确定它是否提供了我通过情节提要嵌入 VC 的详细信息,但是看到下面的 smartcats 评论,我想我需要在其他地方重新组织我继承的委托......父母?
  • 当您说父视图控制器包含其他3个视图控制器时,您的意思是您已经明确地在它们之间建立了父子关系?或者你的意思是所有 3 个视图控制器都是从父视图控制器导航到的?

标签: ios swift uiviewcontroller delegates delegation


【解决方案1】:

不幸的是,我不知道 Xcode 中的拖放是如何工作的,我在代码中做所有事情。但是,当您的父视图控制器实例化另一个视图控制器时,只需将父视图控制器设置为容器的委托。

创建协议:

protocol SomeProtocol: AnyObject {
    func passX(a: String?)
    func passY(b: String?)
}

容器将具有该协议类型的委托:

class FirstContainerVC: UIViewController {
    weak var delegate: SomeProtocol?
}

class SecondContainerVC: UIViewController {
    weak var delegate: SomeProtocol?
}

父级必须符合协议才能成为委托。然后,当您实例化容器时(在这种情况下您只能执行一次),将 self 设置为它们的代表:

class ParentViewController: UIViewController, SomeProtocol {

    // make the containers instance properties so that you
    // can access them from the protocol methods
    weak var firstContainerVC = FirstContainerVC()
    weak var secondContainerVC = SecondContainerVC()

    // set the delegates at some point
    func setDelegates() {
        firstContainerVC?.delegate = self
        secondContainerVC?.delegate = self
    }

    func passX(a: String?) {
        guard let a = a else {
            return
        }
        secondContainerVC?.getFromFirst(a: a)
    }

    func passY(b: String?) {
        //
    }

}

然后当你想从第一个到第二个时,通过委托从第一个容器到父容器,从父容器到第二个容器。

class FirstContainerVC: UIViewController {

    weak var delegate: SomeProtocol?

    func sendToSecond() {
        delegate?.passX(a: "slick")
    }

}

class SecondContainerVC: UIViewController {

    weak var delegate: SomeProtocol?

    func getFromFirst(a: String) {
        print(a)
    }

}

这是一个有点粗略的例子。您应该以您感觉最舒服的方式编写实现代码(即优雅地展开、实例化的方式/位置等)。此外,如果所有视图控制器都是永久视图控制器(意味着它们永远不会被释放),则无需将它们设为weak var。不管你怎么做,概念都是一样的。 parent是容器的delegate,容器之间通过parent进行通信。

有些人可能会建议使用通知观察者或单例来让容器相互通信,但我发现当你有一个父级时,这有点矫枉过正。

【讨论】:

  • 欣赏清晰的演练,但是按照以下方式重新排列了我的代码,不幸的是我仍然没有看到从父级触发的协议函数以及随后的接收/结束容器控制器函数..任何其他建议或者我可以展示一下?
  • 如果FirstContainerVC 想向SecondContainerVC 发送内容,第一个容器使用委托delegate?.passX(a: "slick") 将该内容发送给父级。该方法在父级中调用。然后父级使用secondContainerVC?.getFromFirst(a: a) 将其传递给第二个视图控制器。
  • 我发现了我的问题...需要在父 prepareForSegue 方法中将 firstContainerVC 的委托分配给父 stackoverflow.com/questions/27235071/… 感谢让我朝着正确的方向前进!
【解决方案2】:

我同意@slickdaddy 的观点,即您的第二个容器视图控制器无法实例化您的第一个容器视图控制器。我怀疑你已经有了第一个容器 VC,现在你有 2 个。

要回答您关于传递数据的最佳方式的问题,您的容器视图控制器应该对父视图控制器一无所知。通过委托或父级注册的回调,数据应该发送到父级,然后父级应该将其路由到其他感兴趣的包含视图控制器。

让您的层次结构“向下”流动。换句话说,被包含或拥有的 VC 不应该知道他们的所有者或父母的任何事情。它将有助于重用、组织等。

还可以考虑另一种方法:将相同的模型对象传递给每个包含的视图控制器。

最后,我首选的方法是让每个视图控制器(或者实际上是它的视图模型,如果使用 MVVM)到达此类模型对象所在的 DependencyManager 单例。如果做得好,单元测试仍然可以通过将模拟模型注入 DependencyManager 来完全控制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多