How to pass prepareForSegue: an object

IosXcodeUitableviewMapkitStoryboard

Ios Problem Overview


I have many annotations in a mapview (with rightCalloutAccessory buttons). The button will perform a segue from this mapview to a tableview. I want to pass the tableview a different object (that holds data) depending on which callout button was clicked.

For example: (totally made up)

  • annotation1 (Austin) -> pass data obj 1 (relevant to Austin)
  • annotation2 (Dallas) -> pass data obj 2 (relevant to Dallas)
  • annotation3 (Houston) -> pass data obj 3 and so on... (you get the idea)

I am able to detect which callout button was clicked.

I'm using prepareForSegue: to pass the data obj to the destination ViewController. Since I cannot make this call take an extra argument for the data obj I require, what are some elegant ways to achieve the same effect (dynamic data obj)?

Any tip would be appreciated.

Ios Solutions


Solution 1 - Ios

Simply grab a reference to the target view controller in prepareForSegue: method and pass any objects you need to there. Here's an example...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

REVISION: You can also use performSegueWithIdentifier:sender: method to activate the transition to a new view based on a selection or button press.

For instance, consider I had two view controllers. The first contains three buttons and the second needs to know which of those buttons has been pressed before the transition. You could wire the buttons up to an IBAction in your code which uses performSegueWithIdentifier: method, like this...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {
    
        // Get destination view
        SecondView *vc = [segue destinationViewController];
    
        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];
    
        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

EDIT: The demo application I originally attached is now six years old, so I've removed it to avoid any confusion.

Solution 2 - Ios

Sometimes it is helpful to avoid creating a compile-time dependency between two view controllers. Here's how you can do it without caring about the type of the destination view controller:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:)                                               withObject:myData];
    } 
}

So as long as your destination view controller declares a public property, e.g.:

@property (nonatomic, strong) MyData *myData;

you can set this property in the previous view controller as I described above.

Solution 3 - Ios

In Swift 4.2 I would do something like that:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}

Solution 4 - Ios

I have a sender class, like this

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

I use this sender class for passing objects to prepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
	MySenderEntry *sender = [MySenderEntry new];
	sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
		NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
		MySenderEntry *senderEntry = (MySenderEntry*)sender;
		MyEntry *entry = senderEntry.entry;
		NSParameterAssert(entry);
		
        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
		return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
		// ...
		return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
		// ...
		return;
    }
}

Solution 5 - Ios

I came across this question when I was trying to learn how to pass data from one View Controller to another. I need something visual to help me learn though, so this answer is a supplement to the others already here. It is a little more general than the original question but it can be adapted to work.

This basic example works like this:

enter image description here

The idea is to pass a string from the text field in the First View Controller to the label in the Second View Controller.

First View Controller

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    
    // This function is called before the segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        
        // get a reference to the second view controller
        let secondViewController = segue.destinationViewController as! SecondViewController
        
        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

#Second View Controller

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

#Remember to

  • Make the segue by control clicking on the button and draging it over to the Second View Controller.
  • Hook up the outlets for the UITextField and the UILabel.
  • Set the first and second View Controllers to the appropriate Swift files in IB.

#Source

How to send data through segue (swift) (YouTube tutorial)

#See also

View Controllers: Passing data forward and passing data back (fuller answer)

Solution 6 - Ios

For Swift use this,

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
	var segueID = segue.identifier
	
	if(segueID! == "yourSegueName"){
	
        var yourVC:YourViewController = segue.destinationViewController as YourViewController

		yourVC.objectOnYourVC = setObjectValueHere!
		
	}
}

Solution 7 - Ios

I've implemented a library with a category on UIViewController that simplifies this operation. Basically, you set the parameters you want to pass over in a NSDictionary associated to the UI item that is performing the segue. It works with manual segues too.

For example, you can do

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

for a manual segue or create a button with a segue and use

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

If destination view controller is not key-value coding compliant for a key, nothing happens. It works with key-values too (useful for unwind segues). Check it out here https://github.com/stefanomondino/SMQuickSegue

Solution 8 - Ios

My solution is similar.

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}

Solution 9 - Ios

Just use this function.

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data
   
}

Solution 10 - Ios

I used this solution so that I could keep the invocation of the segue and the data communication within the same function:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

A use case would be something like:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

This seems to work for me, however, I'm not 100% sure that the perform and prepare functions are always executed on the same thread.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionchizzleView Question on Stackoverflow
Solution 1 - IosSimonView Answer on Stackoverflow
Solution 2 - IosTotoroTotoroView Answer on Stackoverflow
Solution 3 - IosRemy CiliaView Answer on Stackoverflow
Solution 4 - IosneoneyeView Answer on Stackoverflow
Solution 5 - IosSuragchView Answer on Stackoverflow
Solution 6 - IosMohammad Zaid PathanView Answer on Stackoverflow
Solution 7 - IosStefano MondinoView Answer on Stackoverflow
Solution 8 - IosAlvin GeorgeView Answer on Stackoverflow
Solution 9 - IosParth BarotView Answer on Stackoverflow
Solution 10 - IosdannrobView Answer on Stackoverflow