容器视图控制器之间的委派

Delegation Among Container View Controllers

我有一个父 viewcontroller 托管 3 个容器 viewcontroller。

在某些时候,我需要将数据从一个容器 viewcontroller 传递到另一个容器 viewcontroller,我认为我可以通过委托模式来完成此操作。但是,我似乎无法弄清楚为什么没有触发委托并且接收容器viewcontroller 没有收到任何数据。

似乎无法发现我的设置方式可能存在的问题。如果有推荐的方法在容器之间传递数据,我也会洗耳恭听!

下面是有关设置的代码摘要:

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 的观点,您的第二个容器视图控制器与实例化您的第一个容器视图控制器无关。我怀疑您已经有了第一个容器 VC,现在您有 2.

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

保持对层次结构的了解"downwards"。换句话说,包含或拥有的 VCs 不应该知道他们的所有者或 parents 的任何信息。它将有助于重用、组织等。

还要考虑另一种方法:将相同的模型 object 传递到每个包含的视图控制器中。

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

不幸的是,我不知道 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)
    }

}

这是一个有点粗糙的例子。您应该按照您感觉最舒服的方式对您的实现进行编码(即优雅地展开,实例化 how/where 等)。此外,如果所有视图控制器都是永久视图控制器(意味着它们永远不会被释放),则无需使它们 weak var。不管你怎么做,概念都是一样的。父级是容器的委托,容器之间通过父级进行通信。

有些人可能建议使用通知观察者或单例让容器相互通信,但我发现当你有一个父容器时,这就太过分了。