iOS delegate not working with performSegueWithIdentifier? - ios

I have two controllers (first,second) in a storyboard, xcode 4.2.
First controller has a tableview and embedded in navigation controller.
Second controller has a tableview too and embedded in navigation controller (not same as the first)
In first.h:
#import "second.h"
...
#interface first : UIViewController <secondDelegate, UITableViewDelegate, UITableViewDataSource>
...
In first.m:
- (IBAction)add:(id)sender // action when tapped a button on topbar
{
[self performSegueWithIdentifier:#"addSegue" sender:sender];
}
....
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"addSegue"])
{
NSLog(#"delegated");
second *controller=[segue destinationViewController];
controller.delegate=self;
}
}
- (void)callback
{
NSLog(#"Callback here");
}
Segue is a modal segue with default transition.
second.h:
#protocol secondDelegate
-(void)callback;
#end
....
id <secondDelegate> delegate;
#property (nonatomic,assign) id <secondDelegate> delegate;
second.m:
... (button of topbar tapped action) ...
[self dismissModalViewControllerAnimated:YES];
NSLog(#"class: %#",[self delegate]);
[[self delegate]entryGroupDoneButtonTapped];
Summary:
I don't see the "callback here" message, but I've got a "delegated" message. The "class: " debug line print "null".
Why?
(I can send any data from first to second with this, only delegate's callback not works)

I found a solution: the destinationViewController returns a UInavigationController, so we can use: AddDrinkViewController *controller=[[[segue destinationViewController]viewControllers]objectAtIndex:0];

Related

Delegate methods not responding

I'm having some trouble getting a viewcontroller to respond to a action inside a modal viewcontroller.
I have a sidebar with a settings button. This button presents a settings viewcontroller modally, and I want my sidebar to respond when a user taps the log out button on my settings viewcontroller.
In my settingsTableViewController.h I set up the delegate like this:
#class SettingsTableViewController;
#protocol SettingsTableViewControllerDelegate <NSObject>
- (void)loggedOutUser:(SettingsTableViewController *)viewController;
#end
#interface SettingsTableViewController : UITableViewController
#property (nonatomic, weak) id <SettingsTableViewControllerDelegate> delegate;
....
And then in the settingsTableViewController.m I synthesize the delegate and call the delegate method like so:
#synthesize delegate;
....
- (IBAction)logOut:(id)sender {
[self.delegate loggedOutUser:self];
....
}
Furthermore, in my responding menuTableViewController.h I set it up like so:
#interface MenuTableViewController : UITableViewController <SettingsTableViewControllerDelegate>
And then finally I set the delegate in the prepareForSegue method in my menuTableViewController.m:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
....
if ([[segue identifier] isEqualToString:#"settingsSegue"]) {
SettingsTableViewController *stvc = [segue destinationViewController];
stvc.delegate = self;
}
....
}
I simply cannot figure out what's causing this.
My guess is that the stvc.delegate = self doesn't do what it's supposed to, because the menuTableViewController responds to the delegate of another viewcontroller as well (not modal), and here I had to set the delegate = self in the viewDidLoad method, but before the [self viewDidLoad] call, as placing it after did not work.
Any help that could resolve this issue would be greatly appreciated! I've been struggling with this for too long now... Thanks!
Turns out my destinationViewController is actually a navigationController, so the delegate is not set correctly. Thanks to remus for telling me to set a breakpoint to check if the delegate was set correctly.
I fixed it by writing
SettingsTableViewController *stvc = ((UINavigationController *)[segue destinationViewController]).viewControllers[0];
instead.

Xcode - Using Delegate and Segue to Unlock button in first ViewController

I have this simple project where, when a button on a second ViewController (SecondViewController) is pressed a Delegate function send a string to the first ViewController and Unhide a new button which is not visible.
I have no problem now doing this however, if I add a third view between these to windows the function stops working.
Here what I mean:
In order to do this I use
In ViewController.h:
#interface ViewController : UIViewController <SecondViewControllerDelegate>
In ViewController.m I implemented a Segue function which detected an Identifier and send the value to second view :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"to2"]) {
SecondViewController *SecondView = segue.destinationViewController ;
SecondView.delegate = self;
}
}
-(void)done:(UIButton*)name{
[self dismissViewControllerAnimated:YES completion:nil];
NSLog(#"back to first view, name=%# ", name);
level2But.hidden = NO;
}
To return to the first window i have created a returnButton in SecondViewController.h:
#protocol SecondViewControllerDelegate <NSObject>
-(void) done:(UIButton*)returnButton; //variable passed to ViewController
#end
#interface SecondViewController : UIViewController{
IBOutlet UIButton *returnButton;
id delegate; //declare delegate as an object
}
#property (nonatomic, strong) id <SecondViewControllerDelegate> delegate;
-(IBAction)returnButtonPressed:(id)sender;
In SeconViewController.m I have:
-(IBAction)returnButtonPressed:(id)sender{
[self.delegate done:returnButton];
}
This code is working just fine However if I had a third View It stops Working.
This is not working anymore.
AnySuggestion? Any Help?
This is the project file:
http://goo.gl/3rJOje
I did checked your code and I could see the self.delegate is nil and hence you are not able to move in SecondViewController.m.
-(IBAction)returnButtonPressed:(id)sender{
[self.delegate done:returnButton];
}
so make sure you pass the delegate.
Also if you want to know how to pass the data(delegate) then go through the below tutorial :
http://www.appcoda.com/storyboards-ios-tutorial-pass-data-between-view-controller-with-segue/

Custom Delegate Callback

I'm new to iOS programming and I'm facing a problem
I'm having a problem with custom delegate.
I'm trying to make a simple custom where it return data to the previous view controller and pop the current view controller.
I have 2 navigation view controller
1 - main view controller
2 - Adding
and here is the protocol that is written in the adding view controller
#protocol AddingDelegate <NSObject>
#required
-(void)setInformation:(Adding *)controller withObject:(Conference *)info;
and here is the where I called it in adding view controller
-(IBAction)addingConference
{
NSLog(#"Adding Button Pressed");
conferenceObject = [[Conference alloc]init];
conferenceObject.name = [NameTX text];
conferenceObject.city = [CityTX text];
conferenceObject.description = [Dectription text];
NSMutableArray *info = [[NSMutableArray alloc] init];
[info addObject:conferenceObject];
[self.delegate setInformation:self withObject:conferenceObject];
NSLog(#"adding Conference method is done");
}
I wrote the delegate at the interface in the main view controller
#interface MainViewController : UITableViewController <AddingDelegate>
#end
and here where I declared the delegate method
-(void)setInformation:(Adding *)controller withArray:(NSMutableArray *)info
{
NSLog(#"in the main view at the delegate");
[self.navigationController popToRootViewControllerAnimated:YES];
NSLog(#"Should be popped right now");
}
and this is the prepare for segue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddObject"]) {
UINavigationController *navigation = segue.destinationViewController;
Adding *addingViewController = [[navigation viewControllers]objectAtIndex:0];
addingViewController.delegate = self;
}
}
now the problem is when I push the adding on top of the stack and then fill the information and press done the adding view controller doesn't pop to show main view controller.
I tried to log everything and the logs from the main view controller doesn't show .
Please help me
What I notice here is that in the implementation of prepareForSegue:sender: the segue's destinationViewController is a navigation controller. This makes me think that your segue is not pushing the AddingController on the current navigation stack but it's presenting a new one instead. This means the new navigation controller containing the AddingController is presented modally and as such, when you try to pop the navigation stack nothing seems to happen because you're operating on the wrong navigation stack. If that is the case you have two options: 1. change [self.navigationController popToRootViewControllerAnimated:YES]; for [self dismissViewControllerAnimated:YES completion:nil]; or 2. change the segue to be a push segue instead of a modal segue and point the segue directly to the AddingController.
In Adding.m
#class Adding;
#protocol AddingDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface Adding : UIViewController
#property (weak, nonatomic) id <AddingDelegate> delegate; // have you forgot this one
#end
and use
[self dismissViewControllerAnimated:YES completion:nil];
You need dismiss if you want get back to previous screen and make sure you have added Navigation controller

iOS Modal Segue drops source ViewController?

When doing a modal segue, does the originating ViewController get discarded after the segue is performed? I am setting the destination controller's delegate to the source ViewController, but when the destination ViewController.viewDidLoad, the self.delegate is nil...
The following code will produce the log message "ListViewController.viewDidLoad: My delegate is nil :("
[Source] MapViewController:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"mapToList"]){
NSLog(#"MapViewController.prepareForSegue: Segue mapToList being called, setting LisViewController's delegate to myself");
[segue.destinationViewController setDelegate:self];
if(!self){
NSLog(#"MapViewController.prepareForSegue: I am nil.");
} else {
NSLog(#"MapViewController.prepareForSegue: I am NOT nil.");
}
}
}
[Destination] ListViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
if(!self.delegate){
NSLog(#"ListViewController.viewDidLoad: My delegate is nil :(");
} else {
NSLog(#"ListViewController.viewDidLoad: My delegate populated");
}
}
Your code seems correct, the only thing I have done differently is test this in a skeleton framework I have that is a tableviewcontroller nested in a navigationcontroller. I just tested with the following code and it works fine for me:
RootViewController .h:
#interface RootTableViewController : UITableViewController <newTest>
Prepare for Segue (in rootViewController):
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"segueToModalView"]){
[segue.destinationViewController setDelegate:self];
}
}
Top of Modal View Controller .h:
#protocol newTest <NSObject>
-(void) hello;
#end
Property Declaration in Modal View:
#property (nonatomic, strong) id <newTest> delegate;
ViewDidLoad in Modal View:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.delegate);
}
My NSLog of self.delegate properly prints out and my code appears to be more or less the same as yours. Is your property declared correctly?
This is an old question but I came upon it when running into the same issue myself. Couple of things here:
To the guy who didn't understand why someone would want to use a Nav controller with a modal display - its to get the benefit of the nav bar without having to embed a UINavigationBar into your own view controller like tw airball did.
To solve the problem without resorting to what tw airball did remember that the destination view controller for the segue in this case is the navigation controller...not the view controller embedded in the nav.
So the fix is in your prepareForSeque:
UINavigationController *navController = segue.destinationViewController;
MyRealDestViewController *myRealDestViewController = (MyRealDestViewController)navController.topViewController;
myRealDestViewController.delegate = self;
If the segue is to a NavigationController then the destinationViewController loses the delegate.
I got around this problem by having the modal segue into the destinationViewController, and then adding NavigationBar and Bar Buttons to simulate the navigation controller (I assume you wrapped the destinationViewController in a NavigationController for the "done" and "cancel" buttons).
Set the delegate as normal in the rootViewController:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"segueToModalView"]){
[segue.destinationViewController setDelegate:self];
}
}
Hope that helps

UIPopOverController + UITableView - Hide popover when cell is selected

In my Popover controller, i'm having a table view. On selection of a cell, I want to hide the pop over.
How can I achieve it.
In Header file of Root view controller:
#property (strong, nonatomic) UIStoryboardPopoverSegue* popSegue;
In the implementation file:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [[segue identifier] isEqualToString:#"popover"] )
{
NSLog(#"%#",[segue destinationViewController]);
self.popSegue = (UIStoryboardPopoverSegue*)segue;
[[segue destinationViewController] setDelegate:self];
}
}
When ever you want to hide the pop over:
if ([self.popSegue.popoverController isPopoverVisible])
{
[self.popSegue.popoverController dismissPopoverAnimated:YES];
}
In the table view, add a delegate and implement the delegate in root view controller. When the delegate method is called, use above code to dismiss the pop over.
Allow me to suggest a slightly different solution, which consists in passing the popover controller reference instead of the segue reference.
In the implementation file of the source view controller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue destinationViewController] isKindOfClass:[MyDestViewController class]]) {
MyDestViewController* viewController = (MyDestViewController*)[segue destinationViewController];
UIStoryboardPopoverSegue* popoverSegue = (UIStoryboardPopoverSegue*)segue;
[viewController setPopoverController:[popoverSegue popoverController]];
}
}
In the header file of the destination view controller:
#property (weak, nonatomic) UIPopoverController* popoverController;
In the implementation file of the destination view controller:
#synthesize popoverController;
Same file, whenever you want to dismiss the popover:
[popoverController dismissPopoverAnimated:YES];
The apple docs recommend the following:
Dismissing a popover programmatically requires a pointer to the popover controller. The only way to get such a pointer is to store it yourself, typically in the content view controller. This ensures that the content view controller is able to dismiss the popover in response to appropriate user actions.
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/Popovers.html
in didSelectRowAtIndexPath try this code
[viewController.popoverController dismissPopoverAnimated:YES];

Resources