I've been playing around with custom segues in iOS and am trying to use them as much as possible to allow the complete workflow of the application to be visualised in my storyboards. When I create say a popover segue, it knows about the view triggering the segue (it must in order to position the popover), but when I create a custom segue, I cannot find a way of doing the same. Is there a way of accessing the view that initiated the segue in a custom segue? Also, is there a way of passing custom parameters to a segue from Interface Builder, much like you can pass runtime arguments to a view controller?
You can access to the View that has triggered a custom segue by implementing the method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
... on your View Controller.
On that method, the value of sender will be the view that triggered the segue, if you linked it using Interface Builder. When implementing this method, it is recommended to query what segue has been triggered in the following way:
if ([[segue identifier] isEqualToString:#"segueid"])
... where "segueid" would be the identifier you have given to your segue in Interface Builder.
About your second question, I don't know any way to specify parameters for a segue in Interface Builder, but you can use the same "prepareForSegue" method, to pass them from your View Controller at Runtime.
Imagine that your custom segue has a property called animationStyle
if the perform method, you can have the following:
- (void)perform
{
switch (self.animationStyle) {
case 0:
// TODO Perform animation type 0
case 1:
// TODO Perform animation type 1
}
}
Then, let's say you have a couple of View Controllers where you want to use that custom segue. In the first one you can implement the performSegue method like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"yourCustomSegueID"]) {
((YourCustomSegueClass *)segue).animationStyle = 0;
}
}
While in the second view controller you can implement it like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"yourCustomSegueID"]) {
((YourCustomSegueClass *)segue).animationStyle = 1;
}
}
... So effectively, you are reusing the same custom segue class for getting different effects. It is still true that IB will not let you configure the segue directly, but there's no way around that as far as I know.
Related
I am creating a simple game that has a specific image,like a menu button, with a tap gesture. The tap gesture calls a method and goes to a View controller(menu of my game). My problem is when I tap this image, it is ignoring the second action. The image below describes better my tap gesture.
PS: getBackToMenu is my method that sets some attributes of my game.
what you are doing here is triggering segue directly from button. Because of this segue is being performed first.
Do One thing remove segue from button to view controller and create segue between controllers with some identifier.
then implement this method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_IDENTIFIER"])
{
YourViewController *vc = [segue destinationViewController];
[vc setMyObjectHere:object];
}
}
Then on button press event perform segue using this method
- (IBAction)buttonPressed:(id)sender{
//Do your primary task here Then Call performseguewithidentifier method
[self performSegueWithIdentifier:#"YOUR_SEGUE_IDENTIFIER" sender:sender];}
When you are about to perform the segue action, you can add some codes in
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
You can get the destination controller using segue.destinationController, and then set some attribute there as just passing some data.
By the way, you can identify which segue works, add
if ([segue.identifier isEqualToString:#"yourSegueName"])
Is there a way to have a different prepareForSegue's for different segues coming out the same view controller?
Because I have 2 segues coming out of one view, and there obviously are some workarounds, but I was wondering if it was possible to separate the prepareForSegues into 2 entirely separate methods depending on the segue called.
No, you cannot use two different methods.
You can however call two different methods in a conditional statement like bellow:
You can check which segue was invoked:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"addNewCheckListItem"]) {
} else if ([segue.identifier isEqualToString:#"showExistingCheckListItem"]) {
}
}
But make sure you also set them an identifier from Interface Builder
I have a view controller namely DetailViewController in which is embedded a container view controller, IndividualDetailsController.
I would like to know whether is it possible that some change in the DetailViewController could bring about changes in the container view controller i.e, the IndividualDetailsController.
For eg, I would want a button click in the DetailViewController to change a text field value in the IndividualDetailsController controller. Is it possible to do so using IBActions? Any help would be much appreciated.
In the method
prepareForSegue
of DetailViewController keep a reference to the embedded one (IndividualDetailsController) in a property of IndividualDetailsController.
Then from an action in DetailViewController you can, for example, change a property of the IndividualDetailsController that can then change its interface accordingly.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MyEmbedSegue"])
{
self.individualDetailsController = (IndividualDetailsController*)[segue destinationViewController];
}
}
then in the action
self.individualDetailsController.textFieldValue = newValue
This is probably a basic question - but I cant seem to find the answer to it in my searches!
I have a uiview setup which contains two input areas which are linked to a child modal view via separate segues.
this is my parent prepare for segue method -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"goalInfo"])
{
[segue.destinationViewController setYourGoalViewController:self];
}
if ([segue.identifier isEqualToString:#"longGoalInfo"])
{
[segue.destinationViewController setYourGoalViewController:self];
}
}
basically i'd like to determine which segue had been used in the child view so I can apply the relevant filed updates and alter a title/description in the child view. - I basically need something very similar to
if ([segue.identifier isEqualToString:#"goalInfo"])
but i'm not sure how to access this from teh child? Any tips?
The segue identifier is check on the source ViewController during its prepareForSegue: method. What you rather need is during prepare for segue is to set properties on the destination viewController and then when it loads, read these properties and set UI outlets.
Look at this example: I am stuck at presenting a full image on tapping the cell in UICollectionViewController. It's about CollectionVC and its detailVC, but the principle is the same.
I have a view controller with 2 different segues that goes to 2 different view controller,and i have to implement the cancel button in both the controllers.When i press the cancel button,in both the controller,the view will return to the initial view controller.My question is how can i implement the buttons?When i try with this code the compiler warning:Multiple declaration of method "cancel:" found and ignored.Thank you.
interface:
-(IBAction)cancel:(UIStoryboardSegue *)segue;
-(IBAction)done:(UIStoryboardSegue *)segue;
-(IBAction)cancel:(UIStoryboardSegue *)segue;
implementation:
-(IBAction)done:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"ReturnInput"]){
AddSightingViewController *addController = [segue sourceViewController];
if (addController.birdSighting) {
[self.dataController
addBirdSightingWithSighting:addController.birdSighting];
[[self tableView]reloadData];
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
-(IBAction)cancel:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"CancelInput"]){
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
I'm not sure of what you're trying to do. But I think the cancel method needs to be in the 2 child View Controllers, not in the main one. One for each controller (and one cancel button for each view). That way you won't have any problems with multiple declarations of a method.
From your code I conclude that you are using (or want use) exit segues for canceling.
First, you should only have one method declaration and implementation for your cancel method in the initial view controller. In your storyboard create exit segues by control-dragging from your cancel buttons to the green exit icon blow the view controller and select the cancel method defined in the initial view controller. Do that for both view controllers. You should also give your exit segues different identifiers in your storyboard (you need to select the segue in the Document Outline to change its identifier).
Then your cancel method in your initial view controller can look something like this:
-(IBAction)cancel:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"CancelInput1"]) {
// Do something
} else if([[segue identifier] isEqualToString:#"CancelInput2"]) {
// Do something different
}
}
If you don't want to do anything when canceling just leave the method empty.
If you wan't to go back you need to implement an unwind segue.
To do this, define a method to go back on the original view controller (the one you want to go back). You can leave the method empty.
- (IBAction)methodName:(UIStoryboardSegue *)segue
{
}
Then on IB ctrl + drag from the button (or from the view controller) to the green "exit" icon. Select the methodName from the popup menu. If you did it from the view controller set the identifier on the segue and call it with performSegueWithIdentifier: from the button action.
Considerations:
The method name will be detected in every view controller on the storyboard.
You can define the same method name in different view controllers, but when you execute the unwind segue, you will go back to the most recent on the navigation path.