Before storyboards I was able to set delegates and datasources just by dragging an outlet to a class. With storyboards, I cannot drag the outlet to another view controller; there is no destination that will respond to it.
If I click on a view controller object, I am able to see the class owner at the bottom, but as soon as I select the other view controller containing the outlet, the old selection is gone, so I cannot connect the two.
Is this Apple's way of saying we should only connect them programmatically?
Correct. Set the delegate or other data in your prepareForSegue:sender: method. Here is an example:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Check the segue identifier
if ([segue.identifier isEqualToString:#"showDetail"])
{
// Get a reference to your custom view controller
CustomViewController *customViewController = segue.destinationViewController;
// Set your custom view controller's delegate
customViewController.delegate = self;
}
}
If your storyboard segue destination View Controller is an UIViewController then #Marco answer is right. But if your destination View Controller is a UINavigationViewController then you have to get the UIViewController from UINavigationViewController :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Check the segue identifier
if ([segue.identifier isEqualToString:#"chooseCategoryType"])
{
// Get a reference of your custom view controller if your segue connection is an UIViewController
// CustomViewController *customViewController = segue.destinationViewController;
// Get a reference of your custom view controller from navigation view controller if your segue connection is an UINavigationViewController
CustomViewController *customViewController = [[[segue destinationViewController] viewControllers] objectAtIndex:0];
// Set your custom view controller's delegate
customViewController.delegate = self;
}
}
Related
I have a project where I have set up a protocol to pass information back from one TableViewController to a ViewController. Everything worked fine and as expected, but I decided to embed in a Navigation Controller to the TableViewController so I could add a "DONE" barButtonItem to dismiss the Controller when the user is done. Since embedding in the navigation controller, the button works well, the TablieViewController looks identical, but none of its features and methods that use the Protocol and Delegate work, and if I remove the NavigationController everything works. Could someone explain how I can fix this issue? I am fairly new to iOS and objective c.
Here is the prepareForSegue method in the NoteViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController isKindOfClass:[ToolTableViewController class]]) {
ToolTableViewController *targetVC = segue.destinationViewController;
targetVC.toolDelegate = self;
targetVC.autoCorrectIsOn = self.autoCorrectIsOn;
targetVC.undoAvailable = self.undoAvailable;
targetVC.redoAvailable = self.redoAvailable;
}
}
ToolTableViewController.h
#protocol ToolTableViewControllerDelegate <NSObject>
#property (weak, nonatomic) id <ToolTableViewControllerDelegate> toolDelegate;
ToolTableViewController.m - example of a method called
-(void)clearInputText{
// NSLog(#"Clear Method Selected");
[self.toolDelegate didClearInputText];
}
NoteViewController.m
-(void)didClearInputText{
self.noteTextView.text = #"";
[self dismissViewControllerAnimated:YES completion:nil];
}
Since your table view controller is embedded in a navigation controller, it's the navigation controller that will be the destination view controller of the segue. Also, it would be better to use the identifier of the segue for the if statement, rather than the class of the destination view controller (I'm using "SegueToTable" as the identifier, change that to whatever you put for the identifier). Therefore, prepareForSegue should look like this,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"SegueToTable"]) {
UINavigationController *nav = segue.destinationViewController;
ToolTableViewController *targetVC = nav.topViewController;
targetVC.toolDelegate = self;
targetVC.autoCorrectIsOn = self.autoCorrectIsOn;
targetVC.undoAvailable = self.undoAvailable;
targetVC.redoAvailable = self.redoAvailable;
}
}
Your delegate methods are called just fine (based on the sample you pasted).
Since your controllers are embedded in a navigation controller now, you should use:
[self.navigationController popViewControllerAnimated:YES]
Before, you were presenting your controllers modally, that's why dismissViewController worked fine then but not now ( in the context of a nav controller).
I'm trying to use a custom segue (at bottom) to present a view controller modally with a blur view. I need to instantiate the view controller with properties before I present the view controller.
Instating the VC works great when I am using pushVC, but when I use perform segue with identifier, I don't see an option to choose an already instantiated VC.
CustomViewController* VC = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"customVC"];
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
How can I perform the custom segue and force it to use the view controller I allocated (called VC above)?
https://github.com/AlvaroFranco/AFBlurSegue
I need to instantiate the view controller with properties before I
present the view controller.
Why do you have to instantiate CustomViewController before triggering the segue. That shouldn't be necessary, if you need access to a property of CustomViewController before it's shown, you can set it in prepareForSegue.
Try this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"blurSegue"]) {
CustomViewController *customViewController = (CustomViewController *)segue.destinationViewController;
customViewController.propertyToSet = XXX; // set the property here
}
}
Ah, by the way, instead of
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
just use:
[self performSegueWithIdentifier:#"blurSegue" sender:self];
I used containerView in static table cell on StoryBoard.
self.TableViewCell.childViewControllers[0];
self.ContentView.childViewControllers[0];
self.childViewControllers[0];
These had nothing. I want not to use custom UIViewCell.
How can I access in TableViewController?
In your viewController class you can just create array property that will keep references on childViewControllers.
If you add childViewController programmatically, you can just add reference to array in code.
If you use embed segue in storyboard, you can get childViewController by getting destinationViewController of segue in prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"EmbedSegue"]) {
UIViewController *childViewController = segue.destinationViewController;
[self.childViewControllers addObject:childViewController];
}
}
I'm new using storyboards and I'm facing this situation: A uinavigationcontroller contains a view controller (root controller) which contains ten buttons linked each one of then through storyboard to the same view controller.
The behavior of the second view controller depends on the button tapped in the first view controller, but how can identify which button is tapped (like tag value) and pass this info to second view controller?
Thank you.
To add on Daniel's answer:
First, add a public property onto your secondVC that is accessible from your first VC:
#interface SecondViewController : UIViewController
#property (nonatomic) int buttonTagClicked;
#end
You need to set tags up on your UIButtons. This is either done in storyboard or programmatically in your code. I would create a generic IBAction that each button is linked to. You can extract the tag off the button through the sender parameter later.
- (IBAction)buttonClicked:(id)sender
{
[self performSegueWithIdentifier:#"pushSegue" sender:sender];
}
That is linked up to
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"pushSegue"]) {
SecondViewController *destinationVC = (SecondViewController *)[segue destinationViewController];
UIButton *selectedButton = (UIButton *)sender;
destinationVC.buttonTagClicked = selectedButton.tag;
}
}
You can set a segueIdentifier for each connection. Then in your ViewController you could trigger an action based on the identifier you set.
e.g.:
If you select your connection in storyboard you can name it:
And in your ViewController you can trigger an action based on the identifier like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segue1"]) {
UIViewController *destinationVC = [segue destinationViewController];
destinationVC.property = ...;
}
}
I'm using storyboard in my ipad application and successfully able to do transitions, use segues etc.
Currently I am showing pop over view controller on click of a button. I want to detect when the pop over dismisses.
How can I do it?
Here is what I did:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"popover"])
{
UIStoryboardPopoverSegue *pop = (UIStoryboardPopoverSegue*)segue;
pop.popoverController.delegate = self;
}
}
UIPopoverController
Now with my revelation that you're talking about a UIPopoverController, here are the steps:
Setup the UIPopoverController with an appropriate delegate (I'm assuming the "sender" view controller)
Have your "sender" conform to the UIPopoverControllerDelegate
Implement the – popoverControllerDidDismissPopover: message and have any detection logic here
Implement - prepareForSegue:sender: and use the segue's destinationController to both get a reference and set the delegate, something like below:
((MyViewController*)segue.destinationController).delegate = self;
Modal View Controller
Add a delegate to the view controller that is being presented
Name your segue if you haven't already
Have your base view controller implement - prepareForSegue:sender: (refer to the UIViewController documentation)
Assign the sending view controller as the modal view controller's delegate in prepareForSegue:sender:
Call a desired method on the delegate immediately before or after you call dismissModalViewControllerAnimated:
That is how I would approach this. I would also recommend having a formal protocol to conform your sending view controller with.
Create a segue in view controller:
#property (strong, nonatomic) UIStoryboardPopoverSegue* popSegue;
In XIB, create an identifier called "popover" for the view.
In Interface, write the following code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [[segue identifier] isEqualToString:#"popover"] )
{
//[[segue destinationViewController] setDelegate:self];
NSLog(#"%#",[[segue destinationViewController] viewControllers]);
self.popSegue = (UIStoryboardPopoverSegue*)segue;
.
.
.
}
Write the following code to dismiss the pop over by coding:
[self.popSegue.popoverController dismissPopoverAnimated:YES];
Since UIStoryboardPopoverSegueis deprecated in iOS 9, you can use a UIStoryboardPopoverPresentationSegue.
Then in prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)you can set the delegate like this:
Swift:
if let identifier = segue.identifier where identifier == "showPopover" {
let destVC = segue.destinationViewController as! UIViewController
destVC.popoverPresentationController?.delegate = self
}
An Objective-C code for the question is below.
if ([segue.identifier isEqualToString:#"home_login"])
{
UIViewController *dest = segue.destinationViewController;
dest.popoverPresentationController.delegate = self;
}
- (BOOL) popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
{
return NO;
}