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)
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.
This question is related to
ios
xcode
uitableview
mapkit
storyboard
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
}
}
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.
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;
}
}
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
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!
}
}
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
}
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.
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:
The idea is to pass a string from the text field in the First View Controller to the label in the Second 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!
}
}
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
}
}
UITextField
and the UILabel
.How to send data through segue (swift) (YouTube tutorial)
View Controllers: Passing data forward and passing data back (fuller answer)
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
}
}
Source: Stackoverflow.com