0

I have 5 UIViewControllers that I want to pass data from one UIViewController to another. So basically the 3rd - 5th UIViewController is to capture a picture and send it to the server. After that I want to send the preview back to the 2nd UIViewController but unfortunately it didn't work because my UIImageView in the 2nd UIViewController still showing an empty image. Here's my code to pass the image back to the 2nd UIViewController :

func showSuccessPopUp() {
        let destinationVC = VehiclePhotoSuccessPopUpVC(nibName: "VehiclePhotoSuccessPopUpVC", bundle: nil)
        destinationVC.modalPresentationStyle = .overCurrentContext
        destinationVC.okTapped = { (sender) in
            self.dataPass.image = self.photoImage // Passing the image to the model
            let destinationVC = self.navigationController?.viewControllers[3] as! RestructureFormVC
            destinationVC.source = "previewPhoto" // A string for knowing where the source is in the 2nd UIViewController
            destinationVC.dataPass = self.dataPass // Passing the model to the 2nd UIViewController
            self.navigationController?.popToViewController(destinationVC, animated: true)
        }

        self.present(destinationVC, animated: false, completion: nil)
    }

I'm not sure where did I do wrong because I'm still new in iOS development. If you need more code feel free to ask and I will provide it to you. Any help would be appreciated. Thank you.

cleanrun
  • 549
  • 6
  • 20
  • 1
    Does this answer your question? [Passing Data between View Controllers](https://stackoverflow.com/questions/5210535/passing-data-between-view-controllers) – rbaldwin May 13 '20 at 10:23
  • Look at using the Delegate method to pass data back, or Notification Center. – rbaldwin May 13 '20 at 10:24

3 Answers3

1

Edit

After comments, it appears the problem was related to the code never setting the .image property of the image view in the "destination" view controller.


There are different ways to do this...

Your approach should work, but I think you just have the indexing wrong.

A UINavigationController holds a stack of view controllers, starting with the "root" view controller. These are in a zero-based array:

enter image description here

If you change your code as follows:

  • can be confusing to use destinationVC twice, so I changed the first one to popupVC
  • use guard let to make sure you get the right "destination" view controller
  • get the VC at index [1] (not 3)

so...

func showSuccessPopUp() {
    let popupVC = VehiclePhotoSuccessPopUpVC(nibName: "VehiclePhotoSuccessPopUpVC", bundle: nil)
    popupVC.modalPresentationStyle = .overCurrentContext
    popupVC.okTapped = { //(sender) in
        self.dataPass.image = self.photoImage // Passing the image to the model

        //let destinationVC = self.navigationController?.viewControllers[3] as! RestructureFormVC
        // we want to find the Second VC in the stack, which will be [1]
        guard let destinationVC = self.navigationController?.viewControllers[1] as? RestructureFormVC else {
            fatalError("Second VC in navigation stack is NOT a RestructureFormVC")
        }

        destinationVC.source = "previewPhoto" // A string for knowing where the source is in the 2nd UIViewController
        destinationVC.dataPass = self.dataPass // Passing the model to the 2nd UIViewController
        self.navigationController?.popToViewController(destinationVC, animated: true)
    }

    self.present(popupVC, animated: false, completion: nil)
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • thank you for your answer, I've tried to implement your answer into my code but seems like it still doesn't work. I've been trying to use a delegate but it's still confusing for me. could you provide me an example of using a delegate of this problem? thank you! – cleanrun May 13 '20 at 14:35
  • 1
    You'll need to provide some more detail. *"... it still doesn't work ..."* What does that mean? You get an error? No error but no results? You also have the line `self.dataPass.image = self.photoImage // Passing the image to the model` ... what is `dataPass`? – DonMag May 13 '20 at 14:39
  • I got no error but my `UIImageView` on my 2nd controller is still empty where there should've been an image passed on it. the `dataPass` class is a model class where I pass datas and one of them is a `UIImage`. In my understanding, setting the image to the `dataPass` class and pass it to my 2nd controller will provide the `UIImageView` with a `UIImage` on my 2nd view controller. But seems like it doesn't work because when I pass the `dataPass` class the `UIImageView` still have no image – cleanrun May 13 '20 at 14:51
  • 1
    So, you pass an object `dataPass` with an `image` property to your 2nd view controller. Where and when do you set that image to the `UIImageView`'s `.image` property? – DonMag May 13 '20 at 15:09
  • That's correct, but fortunately it's working now. I will answer my own question if you want to know what I did. If you may please correct my answer if you feel like there is something wrong with it. Thank you so much for your help! – cleanrun May 13 '20 at 15:21
  • 1
    @llehcram - I put an edit at the top of my answer explaining what the actual problem / solution was. – DonMag May 13 '20 at 15:42
0

You have to create a delegate which you call before call popToViewController() the 3rd VC implements the delegate and the when you show the 4th and 5th VC you pass the 3rd VC as delegate

Andrea
  • 249
  • 1
  • 5
  • 2
    how to pass that delegate ? from class A to class E ? my stack is A B C D E – Jawad Ali May 13 '20 at 12:37
  • 1
    @jawadAli - Multiple ways to "pass that delegate" ... Add a delegate property to each "interim" VC... `A` sets `B.delege = self`; `B` sets `C.delgate = self.delegate`; `C` sets `D.delegate = self.delgate`; `D` sets `E.delegate = self.delgate` ... now `E`'s `self.delegate` points to `A` -- is just one method. – DonMag May 13 '20 at 16:27
  • Passing delegates , Is not it a bad design strategy? – Jawad Ali May 13 '20 at 16:57
  • 1
    @jawadAli - there are various ways to approach the OP's task... pass delegate, "walk up the nav stack", use a data-manager class, etc. All have pros and cons. "Passing the delegate" through intermediate classes may not be the best approach, but I wouldn't say it is *necessarily* bad design. – DonMag May 14 '20 at 13:00
  • Yeah you are right ... and what about coordinators ? – Jawad Ali May 14 '20 at 13:04
0

For some reason the UIImageView on my 2nd UIViewController is not updating the image because I passed the UIImage in the dataPass model class. I changed the code like this :

func showSuccessPopUp() { // Based on DonMag's answer
    let popupVC = VehiclePhotoSuccessPopUpVC(nibName: "VehiclePhotoSuccessPopUpVC", bundle: nil)
    popupVC.modalPresentationStyle = .overCurrentContext
    popupVC.okTapped = { (sender) in
        // we want to find the Second VC in the stack, which will be [1]
        guard let destinationVC = self.navigationController?.viewControllers[1] as? RestructureFormVC else {
            fatalError("Second VC in navigation stack is NOT a RestructureFormVC")
        }

        destinationVC.source = "previewPhoto" // A string for knowing where the source is in the 2nd UIViewController
        destinationVC.assetPhoto = self.photoImage // Set the image immediately without using the dataPass model class
        self.navigationController?.popToViewController(destinationVC, animated: true)
    }

    self.present(popupVC, animated: false, completion: nil)
}

So here what I did was I just set the UIImage directly to the assetPhoto variable in my 2nd controller. And to update the UIImageView I create a function in my 2nd controller to check whether the assetPhoto variable is nil or not and call it in viewWillAppear like this:

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        setAssetImage()
}

func setAssetImage() {
        if assetPhoto == nil {
            photoParentView.isHidden = true
        } else {
            photoParentView.isHidden = false
            photoImageView.image = assetPhoto
        }
}

And it works as I expected to be.

cleanrun
  • 549
  • 6
  • 20