Search code examples
xcodeuitableviewsegueswift4.2

pass UIimage from UITableViewCell to next ViewController


There are many other topics of passing data to another ViewController - i know - but i could not find the solution for passing data from UITableViewCell to UIViewController. The question differs from others that here i have to access an ImageView in another class of UITableViewCell. Segues, prepare for segues an other topics are discussed in other posts sufficiently but not this special constellation.

I have a class UITableViewCell:

class PostCell: UITableViewCell {
...
// networkService is downloading an image 
networkService.downloadImage({ (imageData) in
            let image = UIImage(data: imageData as Data)
...
// image is set to UIImageView
self.postImageView.image = image

In my ViewController i do this to go to the DetailViewController:

 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    aktIndex = indexPath.section

    performSegue(withIdentifier: "segueDetail", sender: self)
}

I tried this:

 let MainStory:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let desVC = MainStory.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController

    desVC.getImage = ???
    self.navigationController?.pushViewController(desVC, animated: true)

DetailViewController:

class DetailViewController: UIViewController {

var getImage = UIImage()
...

I have made a segue in xcode (segueDetail): enter image description here

At the moment i store the imagedata in UserDefaults and read them again in the DetailViewController. Very weird, i know.

Where do i have to pass the data from? In my PostCell or in the ViewController? The problem is to get access to image-data from PostCell in my ViewController.


Solution

  • In tableView(_:didSelectRowAt:) when you call performSegue(withIdentifier: sender:), you can pass any data or references in it. This is now available in prepare(forSegue:sender:) and your last shot at preparing the data to be passed to the segued viewController.

    Example (Using Segue):

    If segueDetail is properly hooked up via storyboard and your user taps on a row, you could send the indexPath to the segue like:

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "segueDetail", sender: indexPath)true)
    }
    

    Then in prepare(forSegue:sender:), depending on your solution, you can prepare access to the required data that you need to pass to the next viewController like:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let vc = segue.destination as? DetailViewController {
            let indexPath = sender as! IndexPath
    
            let cell = tableView.cellForRow(at: indexPath) as! PostCell
            vc.getImage = cell.postImageView.image
        }
    }
    

    Example (Manually without segue):

    If you are not using a segue and the user taps on a row, you could manually push a viewController with data like:

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let sb = UIStoryboard(name: "Main", bundle: nil)
        let vc = sb.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
    
        let cell = tableView.cellForRow(at: indexPath) as! PostCell
        vc.getImage = cell.postImageView.image
    
        self.navigationController?.pushViewController(desVC, animated: true)
    }
    

    And your DetailViewController should be:

    class DetailViewController: UIViewController {    
        var getImage: UIImage?
        //...
    

    NOTE: This answer is the best I could fit to work with the given content.
    It should just about work but please don't just copy-paste as it's not optimized (for example, your user taps on a cell before it's image is downloaded).
    This was just to show the basics, so please improvise and apply proper case handling.