Search code examples
iosswiftdelegation

iOS communication between to Child Controllers of Collection Controller


I am currently developing an app for iOS written in Swift and built an interface with a UIPageViewController and two child view controllers so far.

Everything works fine, but at some points I trigger the PageViewController to set a different view controller. When this happens I want to pass data from one child to the other.

Now I know that one of the most asked iOS Dev questions is how to pass data between two UIViewControllers but my case is very specific and I could not find a similar question. I would appreciate links if I am wrong. Also I am not just looking for a solution because I found one myself. I am looking for the best one I know this is hard to judge, but at least I am looking for a better one than mine.

So I figured a way out, but I think it is not very elegant. So I am exchanging data through delegates. Basically I direct it from Child View Controller A to the PageViewController to the Child View Controller B via Delegation.

All that just works fine but I don’t know if this is the best way to go for or if there are other much better ways.

Thanks a lot for all your help.


Solution

  • What you did is probably the best way of doing it from all perspective but amount of code that is being used. Since your parent (page view controller) is responsible for all the work it is best to also channel all data it needs. Currently that is between 2 view controllers and later it might be between 3. You might also simply change these view controllers but preserve the protocols you use to retrieve the data.

    But there is a big catch here. If a number of view controllers will grow then you might find yourself in an issue where previous view controllers are being deallocated (if this is not already going on) so at the end there is no way for view controller D to access view controller A simply because A no longer exists.

    What the solution to these things is really depends but from your question I can assume you are passing some data from one view controller to another like onboarding where you are collecting user data through multiple screens. In such case it is best to have a class with all the data needed like:

    class MyData {
        var dataA: DataA?
        var dataB: DataB?
        var dataC: DataC?
    }
    

    Now the page controller is responsible to create such data and pass them to each of these view controllers that will use/modify the data. So in page view controller:

    var myData: MyData = MyData()
    
    func prepareViewControllerA() {
        let controller: ViewControllerA...
        controller.myData = myData
        ...
    }
    

    Now each of the view controllers will have its own property to access the same data object and modify it. You could also add a delegate to your class so page controller may listen to its events:

    protocol MyDataDelegate: class {
        func myData(_ sender: MyData, updatedA: DataA?)
        func myData(_ sender: MyData, updatedB: DataB?)
        func myData(_ sender: MyData, updatedC: DataC?)
        func myDataAreFinalized(_ sender: MyData)
    }
    
    class MyData {
        var dataA: DataA? {
            didSet {
                delegate?.myData(self, updatedA: dataA)
            }
        }
        var dataB: DataB? {
            didSet {
                delegate?.myData(self, updatedB: dataB)
            }
        }
        var dataC: DataC? {
            didSet {
                delegate?.myData(self, updatedC: dataC)
            }
        }
    
        weak var delegate: MyDataDelegate?
    
        func finalize() {
            delegate?.myDataAreFinalized(self)
        }
    
    }
    

    And now your page controller can use it:

    var myData: MyData = {
        let data = MyData()
        data.delegate = self
        return data
    }()
    

    and delegates:

    func myData(_ sender: MyData, updatedA: DataA?) {
    }
    func myData(_ sender: MyData, updatedB: DataB?) {
    }
    func myData(_ sender: MyData, updatedC: DataC?) {
    }
    func myDataAreFinalized(_ sender: MyData) {
        dismiss(animated: true, completion: nil)
    }