unable to receive callback from second view controller - ios

I have got two view controllers. Im trying to pass data to the previous viewcontroller
I have the following code in my second view controller CEPeoplePickerNavigationController
#class CEPeoplePickerNavigationController;
#protocol CEPeoplePickerNavigationControllerDelegate <NSObject>
- (void)previousViewController:(CEPeoplePickerNavigationController *)controller itemToSend:(NSString *)item;
#end
#interface CEPeoplePickerNavigationController : UIViewController <UITableViewDelegate,UITableViewDataSource>{
}
#property (nonatomic, retain) id < CEPeoplePickerNavigationControllerDelegate> peoplePickerDelegate;
#end
When the user clicks the done button, following code will be exectied
- (void)doneAction:(id)sender
{
[self.peoplePickerDelegate previousViewController:self itemToSend:#"From Previous VC"];
[self dismissViewControllerAnimated:YES completion:nil];
}
In my first view controller, I have the following interface in header file and I have ofcourse implemented the previousViewController method in my first view controller where the data has to be received
#interface CallViewViewController : UIViewController<CEPeoplePickerNavigationControllerDelegate>
#end
When I move from the first view controller to the second view controller, Im using the following code.
CEPeoplePickerNavigationController *nextVc = [[CEPeoplePickerNavigationController alloc] init];
nextVc.peoplePickerDelegate = self;
[self presentViewController:nextVc animated:YES completion:nil];
But when the user clicks the done button from the second view controller, Im not receiving any callback in my first view controller. why so?
I have implemented the interface as following,
- (void)previousViewController:(CEPeoplePickerNavigationController *)controller itemToSend:(NSString *)item
{
NSLog(#"from CEPeoplePickerNavigationController %#",item);
}
UPDATE:
Following code works
if ([[CallViewViewController new] respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}
But if I try it by following way, it is not working
if ([[self.viewCrtrlDelegate respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}
This is how Im instantiating the view controller.
CEPeoplePickerNavigationController *nextVc = [[CEPeoplePickerNavigationController alloc] init];
nextVc.viewCrtrlDelegate = self;
[self presentViewController:nextVc animated:YES completion:nil];

Your code seems absolutely correct but to get around all the possibilities.
Can you check whether your done button action has a check to know if the delegate methods is available or not in that class?
if ([self.viewCrtrlDelegate respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}

Related

Custom Delegate with Modal Form Sheet not working

I have gone through most of the previous related posts, but although I have followed them correctly (as far as i understood), I simply am not able to trigger the delegate method for below code.
Objective: ModalView generates a string *SQL_String. Press DONE to dismiss the ModalView and trigger the delegate method in the parentview to get that *SQL_String.
SearchModalViewController.h
#protocol SearchControllerDelegate
- (void)didDismissModalView:(NSString *)SQL_String;
#end
#interface SearchModalViewController : UIViewController
#property (nonatomic, assign) id <SearchControllerDelegate> searchDelegate;
- (IBAction)handleDone:(id)sender;
SearchModalViewController.m
#interface SearchModalViewController ()
#end
#implementation SearchModalViewController
#synthesize searchDelegate;
- (IBAction)handleDone:(id)sender {
[self dismissView:sender];
}
- (void)dismissView:(id)sender {
[searchDelegate didDismissModalView:#"Test"];
[self dismissViewControllerAnimated:YES completion:nil];
}
DetailViewController.m (My parent View Controller)
#interface DetailViewController () <SearchControllerDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SearchModalViewController *searchModal = [[SearchModalViewController alloc] init];
searchModal.searchDelegate = self;
}
PROBLEM:
Below delegate method is not getting triggered.
- (void)didDismissModalView:(NSString *)SQL_String {
[self dismissViewControllerAnimated:YES completion:nil];
NSLog(#"The string = %#", SQL_String);
}
Any idea where I am doing wrong?
EDIT: Thank you guys. With your fast suggestions, I am able to close it down by adding below code instead of my previous IB connection.
- (IBAction)showSearchModal:(id)sender {
SearchModalViewController *searchModal = [self.storyboard instantiateViewControllerWithIdentifier:#"search"];
searchModal.searchDelegate = self;
searchModal.modalPresentationStyle = UIModalPresentationFormSheet;
searchModal.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:searchModal animated:YES completion:nil];
}
Here it goes
Change DetailViewController.m
- (IBAction)pushToSearch:(id)sender{
SearchModalViewController *searchModal = [self.storyboard instantiateViewControllerWithIdentifier:#"search"];
searchModal.searchDelegate = self;
[self presentViewController:searchModal animated:YES completion:nil];
}
And it will work.
Firstly, make sure your dismissView: of the SearchModalViewController is getting triggered.
Secondly, make sure your searchDelegate in the dismissView: method is not nil.
You need to set the delegate when you present the SearchModalViewController. The reason why your code doesn't currently work, is because the modal view controller's delegate is nil.
Update:
You set the delegate in prepareForSegue:sender:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:#"modalSearch"])
{
SearchModalViewController *controller = (SearchModalViewController *)[segue destinationViewController];
controller.delegate = self;
}
}

presentViewController didnt work appdelegate

line presentViewController crash app
#interface VVPassbook : NSObject
#property (nonatomic, retain) id delegate;
-(void)gotPassbookFromUrl:(NSURL *)passbookUrl;
#end
#import "VVPassbook.h"
#implementation VVPassbook
-(void)gotPassbookFromUrl:(NSURL *)passbookUrl
{
//present view controller to add the pass to the library
PKAddPassesViewController *vc = [[PKAddPassesViewController alloc] initWithPass:pass];
[vc setDelegate:(id)self.delegate];
[self.delegate presentViewController:vc animated:YES completion:nil];
}
#end
im call this method in AppDelegate.m in method
- (void)application:(UIApplication*)application didReceiveRemoteNotification:
(NSDictionary*)userInfo
{
VVPassbook *pass = [[VVPassbook alloc] init];
pass.delegate = self.window.rootViewController;
[pass gotPassbookFromUrl:MYURL ];
}
all times error
reason: 'Application tried to present a nil modal view controller on target <VVRightManuViewController: 0x15dd28460>.'
you should present a viewController from a UIViewController, i.e., self
(if self is a viewcontroller).
Note that you will get a "Attempt to present on whose view is not in the window hierarchy"-warning when self (this viewcontroller) is detached from the Main Window.
Solution: always use addChildViewController: to child viewcontrollers.
Why are you using self.delegate to push the view Controller,
simple write
[self presentViewController:vc animated:YES completion:nil];
in the place of
[self.delegate presentViewController:vc animated:YES completion:nil];

Closing dismissViewController doesn't fire the viewWillAppear

I have a view which opens a modal seque View.
I open this view with this code:
- (IBAction)openInfopage:(UIButton *)sender;
{
[self performSegueWithIdentifier:#"Infopage" sender:self.view];
}
I close this View with:
- (IBAction)closeView:(id)sender {
// old version:
//[self dismissViewControllerAnimated:YES completion:nil];
// my new version:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
When the modal is closed, I want to update the view with the new datas the modal view generated.
I use [self.tableView reloadData]; to update, but where can I put this code, so it will start?
I try the viewWillAppear, but this isn't called when I close the modal view.
I always put these things in a delegate-protocol. So just insert this to your modal-viewcontroller.h:
#protocol MyDelegateProtocol <NSObject>
#optional
-(void)modalFinished;
#end
#interface ViewController : UIViewController
#property (nonatomic, weak) id <MyDelegateProtocol> delegate;
#end
And in the .m call this:
if(_delegate) [_delegate modalFinished];
When you are done. In the presenting ViewController you have to omplement this:
<MyDelegateProtocol>
after the #implementation line. And implement the delegate-method -(void)modalFinished. In this method you can do your refresh. And of course set the delegate property from the modal-viewcontroller to self in the presenting view controller.
EDIT:
MyViewController mvc = ...;
MyViewController.delegate = self;
[self presentViewController:...];
and if you present via segue:
in prepareForSegue:
MyViewController *mvc = segue.destinationViewController;
mvc.delegate = self;

Refreshing data in a UIViewController after dismissing its presented modal view controller via delegate

I have the delegate working as the data is being passed from the modal to the presenting view controller. But the presenting view controller isn't showing the data it receives from the modal. I looked at other posts and they say to use the delegate/protocol method, but don't explain how/why the presenting VC refreshes. I'm assuming my delegate is setup incorrectly. Otherwise, what is the method to refresh the data? I've checked and the viewWillAppear and viewDidAppear doesn't get called.
SCCustomerDetailVC.h (Presenting VC)
#import "SCCustomersVC.h"
#interface SCCustomerDetailVC : UIViewController <SCCustomersVCDelegate>
#property (atomic, strong) SCCustomer *customer;
#property (strong, nonatomic) IBOutlet UIButton *changeCustomerButton;
- (IBAction)changeCustomerButtonPress:(UIButton *)sender;
#end
SCCustomerDetailVC.m (Presenting VC)
- (IBAction)changeCustomerButtonPress:(UIButton *)sender
{
UINavigationController *customersNC = [self.storyboard instantiateViewControllerWithIdentifier:#"customersNC"];
SCCustomersVC *customersVC = (SCCustomersVC *)customersNC.topViewController;
customersVC.delegate = self;
[self presentViewController:customersNC animated:YES completion:nil];
}
//Protocol methods
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
//At this point, self.customer has the correct reference
[self dismissViewControllerAnimated:YES completion:nil];
}
SCCustomersVC.h (Modal VC)
#import "SCCustomersVCDelegate.h"
#class SCCustomerDetailVC;
#interface SCCustomersVC : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
#property (weak, nonatomic) id <SCCustomersVCDelegate> delegate;
#end
SCCustomersVC.m (Modal VC)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SCCustomer *customer = [self customerAtIndexPath:indexPath];
[self.delegate passCustomer:customer];
}
SCCustomersVCDelegate.h
#class SCCustomer;
#protocol SCCustomersVCDelegate <NSObject>
#optional
- (void)passCustomer:(SCCustomer *)customer;
#end
I think you're nearly there. EDIT - just learned here that viewWillAppear behavior is different in iOS>5. You still want view will appear to update your view with your model state, since it needs to do that on initial presentation.
And it's fine to call it from either your modal vc or from within the delegate method. So add code to viewWillAppear that updates the view with the view controller's model state...
// SCCustomerDetailVC.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// making up an IBOutlet called someLabel
// making up a model method (description) that returns a string representing your model
self.someLabel.text = [self.customer description];
}
Then either from the presented vc or the delegate, call viewViewWillAppear:
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
[self viewWillAppear:YES];
[self dismissViewControllerAnimated:YES completion:^{}];
}
You should reload your UI after setting the "customer"
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
//At this point, self.customer has the correct reference
[self dismissViewControllerAnimated:YES completion:^{
// reload your UI here or call a method which will reload your ui
// e.g. for tableView it will be [tableView reload];
}];
}

Switching between modal view controllers

My app allows the user to switch between two different modal view controllers (for two different styles of data entry). The code below used to work (in iOS 4.3 and earlier):
UIViewController * parent = current.parentViewController;
[current dismissModalViewControllerAnimated:NO];
svc.modalPresentationStyle = UIModalPresentationFormSheet;
[parent presentModalViewController:svc animated:NO];
[svc release];
but no longer (in iOS 5) - the "current" view controller dismisses, but "svc" is not presented.
Any idea why it broke (i.e. what did I do wrong)?
Any idea how to do it "right" (so that it works on 5.0 as well as 4.3 and earlier)?
Jeff Hay was totally right in his comment except for one thing. You should do it in the -viewDidAppear: method of the view controller which originally presented the first modal view controller.
Example:
// MyViewController.h
#interface MyViewController : UIViewController {
BOOL _shouldPresentSecondModalViewController;
}
#end
// MyViewController.m
#implementation MyViewController
- (void)viewDidAppear:(BOOL)animated {
if(_shouldPresentSecondModalViewController) {
UINavigationController *myNavCon;
// Code to create second modal navigation controller
[self presentModalViewController:myNavCon animated:YES];
_shouldPresentSecondModalViewController = NO;
}
}
- (void)presentFirstViewController {
UINavigationController *myNavCon;
// Code to create the first navigation controller
_shouldPresentSecondModalViewController = YES;
[self presentModalViewController:myNavCon animated:YES];
}
#end
EDIT:
Now, if you want to pass data between the two modal view controllers, you can use a delegate.
// FirstModalViewControllerDelegate.h
#protocol FirstModalViewControllerDelegate
#optional
- (void)controller:(FirstModalViewControllerDelegate *)vc shouldShowData:(id)anyType;
#end
// MyViewController.h
#interface MyViewController : UIViewController <FirstModalViewControllerDelegate> {
id _dataToDisplay;
}
#end
// MyViewController.m
#implementation MyViewController
- (void)viewDidAppear:(BOOL)animated {
if(_dataToDisplay != nil) {
UINavigationController *myNavCon;
// Code to create second modal navigation controller
[self presentModalViewController:myNavCon animated:YES];
[_dataToDisplay release];
_dataToDisplay = nil;
}
}
- (void)presentFirstViewController {
UINavigationController *myNavCon;
FirstModalViewController *myCon;
// Code to create the first modal view controller
[myCon setDelegate:self];
myNavCon = [[UINavigationController alloc] initWithRootViewController:myCon];
[self presentModalViewController:myNavCon animated:YES];
[myNavCon release];
}
- (void)controller:(FirstModalViewControllerDelegate *)vc shouldShowData:(id)anyType {
/* This method will get called if the first modal view controller wants to display
some data. If the first modal view controller doesn't call this method, the
_dataToDisplay instance variable will stay nil. However, in that case, you'll of
course need to implement other methods to, like a response to a Done button, dismiss
the modal view controller */
[self dismissModalViewController];
_dataToDisplay = [anyType retain];
}
#end

Resources