Segue and delegates in UIKit

I have 2 Controllers: MainVC and SideMenuVC.

I wanted to modify MainVC using SideMenuVC, so created delegate of SideMenuVC ( as well, there's Emdebed segue "name..." to "Side Menu View Controller" on storyboard because MainViewController has subView, which contains ContainerView - this container is our SideMenuVC. And this delegate works as he should.

However, due to logic in the app, I also need to send data from MAINVC to SIDEMENUVC.

So i did the same - created another delegate of second VC... But I turned out, MainViewControllerDelegate is not responding in SideMenuViewController. And i'm absolutely clueless...

Yes, i do implement necessary protocols in both classes, in extension!

Code of both VCs below, screens of storyboard in the attachment

MainViewController + MainViewControllerDelegate

protocol MainViewControllerDelegate{
    func isImageLoaded(_ isLoaded:Bool)
}

class MainViewController: UIViewController {
    /* ... */
    
    var delegate: MainViewControllerDelegate?
    var sideMenuViewController: SideMenuViewController?
    
    private var isSideMenuPresented:Bool = false
    private var isImageLoaded:Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.isImageLoaded = false
        self.setupUI()
        self.delegate?.isImageLoaded(false)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "MainVC_SideMenuVC_Segue")
        {
            if let controller = segue.destination as? SideMenuViewController
            {
                self.sideMenuViewController = controller
                self.sideMenuViewController?.delegate = self
            }
        }
    }
/* ... */
//I'm using PHPicker, and when new image is selected, i want to send "true" via delegate
  func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        dismiss(animated: true)
        if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self){
            let previousImage = self.presentedImage.image
            itemProvider.loadObject(ofClass: UIImage.self){ [weak self] image, error in
                DispatchQueue.main.async {
                    guard let self = self, let image = image as? UIImage, self.presentedImage.image == previousImage else {
                        return
                    }
                    self.presentedImage.image = image
                    self.isImageLoaded = true;
                    self.delegate?.isImageLoaded(true)
                }
            }
        }
        
    }

SideMenuViewController + SideMenuViewControllerDelegate

protocol SideMenuViewControllerDelegate{
    func hideSideMenu() 
    func performAction(_ type:OperationType)
}

class SideMenuViewController: UIViewController {
/*...*/
    
    var delegate: SideMenuViewControllerDelegate?
    var mainViewController: MainViewController?
    
    private var menuData: [ExpandingCellModel] = []
    private var isImageLoaded: Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
      //  self.mainViewController?.delegate = self
        menuData = setupData()
        setupUI()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let controller = segue.destination as? MainViewController {
            controller.delegate = self
        }
    }
}

/* ... View of storyboard*/


Here is what I think is happening.

There is segue happening from MainVC to SideMenuVC but there is no segue actually happening between SideMenuVC to MainVC in my opinion.

Happening is keyword because there is an EmbedSegue from MainVC to SideMenuVC but where is the segue from SideMenuVC to MainVC ? You did some connection in storyboard but nothing is happening in my opinion.

That is why in override func prepare is being called as planned in MainViewControllerDelegate and the delegate is getting set but it is not getting set in SideMenuViewController since override func prepare doesn't get called as no segue happens.

What you can do instead which might work is set both the delegates inside prepare in MainViewControllerDelegate

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "MainVC_SideMenuVC_Segue")
        {
            if let sideMenuVC = segue.destination as? SideMenuViewController
            {
                sideMenuVC.delegate = self
                
                // assign MainViewControllerDelegate here
                self.delegate = sideMenuVC
            }
        }
    }

Check now if data is sent back to main view controller also.

If your issue is still not yet solved, please have a look and try this small example I set for you in github to show passing data between mainVC and embeddedVC and it might give you some hints.

You can see the result of this in action here: https://youtu.be/J7C7SEC04_E