UIPopoverController + UINavigationController = Delegate problems - ios

I have two views setup ( inside a TabBar). The DetailView with a button that calls a PopOver with a NavigationController+UITableView (RootView) loading data from CoreData. I have a problem passing data from the UITableView to the DetailView. I have a protocol declared in RootView and used in the DetailView.
Here is the code I use to create the PopOver from the button because I think I have some delegate issues. Any help will be amazing,
- (IBAction)zoneListButtonController
{
if (self.controladorPopOver == nil) {
ipadrootviewController = [[iPadRootViewController alloc] initWithNibName:#"iPadRootView" bundle:[NSBundle mainBundle]];
UINavigationController *ipadnavController = [[UINavigationController alloc]
initWithRootViewController:ipadrootviewController];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:ipadnavController];
self.controladorPopOver = popover;
popover.delegate = self;
self.title = #"Countries";
popover.popoverContentSize = CGSizeMake(320, 300);
[self.controladorPopOver presentPopoverFromRect:CGRectMake(112, 20, 86, 27) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
[ipadnavController release];
[controladorPopOver release];
}
}

An instance of the SubZone1iPadController doesn't exist when you create the popover in DetailView so you can't set its delegate property directly from the DetailView.
One option is to also add the delegate property to the iPadRootViewController which you can set in the zoneListButtonController method. Then, when ipadrootviewController creates the SubZone1iPadController, pass along the delegate.
So in both ipadrootviewController and SubZone1iPadController, add a delegate property:
#property (nonatomic,assign) id <SubZone1Tap> delegate;
Then, in the zoneListButtonController method, set the delegate property on iPadRootViewController:
ipadrootviewController = [[iPadRootViewController alloc] init...
ipadrootviewController.delegate = self;
Then, where ipadrootviewController creates SubZone1iPadController:
SubZone1iPadController *sz1 = [[SubZone1iPadController alloc] init...
sz1.delegate = self.delegate;
[self.navigationController pushViewController:...
[sz1 release];
Finally, in the DetailView, make sure the delegate method is implemented. For example:
-(void)SubZone1Tap:(NSString *)name
{
NSLog(#"SubZone1Tap, name = %#", name);
//dismiss the popover if that's what you need to do...
[controladorPopOver dismissPopoverAnimated:YES];
}

Related

Switching view controllers from UIToolbar subclass

Please excuse my newness in IOS, but I am trying to switch view controllers when someone clicks on a button in my toolbar. For my toolbar I have overridden the UIToolbar and drawn my own custom toolbar. I have four buttons each with their own action something like this:
NSMutableArray *toolbarItems = [#[] mutableCopy];
[toolbarItems addObject:[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"notifications"] style:UIBarButtonItemStyleBordered target:self action:#selector(viewNotifications)]];
I want to be able to do something like:
-(void)viewNotifications
{
NSLog(#"CustomUIToolbar::viewNotifications");
//layoutFlow....
// Show the notifications view controller
NotificationsViewController *rootViewController = [[NotificationsViewController alloc] initWithCollectionViewLayout:layoutFlow];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[self presentViewController:navController animated:YES completion:NULL];
}
The problem with this is clearly that the UIToolbar doesn't directly have access to switching view controllers. Is there a way to access the presentViewController method or something like it from within the custom UIToolbar?
Create a protocol and a delegate and let the UIViewController which creates the UIToolBar implement that delegate.
When the user presses a UIBarButtonItem you send the delegate the message (the main UIViewController) and handle the UINavigationController code there.
#protocol ToolBarProtocol <NSObject>
-(void)didPressButton1;
#end
#property (nonatomic) id <ToolBarProtocol> delegate
And when creating your UIToolBar:
YourToolBar *toolbar = [YourToolBar alloc] init];
toolbar.delegate = self;
Inside your method change to tell the delegate what should happen:
-(void)viewNotifications
{
NSLog(#"CustomUIToolbar::viewNotifications");
//layoutFlow....
if ([self.delegate respondsToSelector:#selector(didPressButton1)])
{
[self.delegate didPressButton1];
}
}

delegate help code not behaving as expected

Really simple question i think.
i have a main view and a popover view.
i am trying to make a custom delegate which will enable me to close the popover view at certain times. My code is posted below. The real simple issue i am having is my code dosnt appear to be entering the delegate code. Any ideas as to why? It builds and runs but nothing appears to happen, i have put NSLog statments, the popover nslog appears but the function in
mainview dismissPopover does nothing.
Mainview.h
#interface MainScreen : UIViewController<DismissPopoverDelegate>
Mainview.m
- (void) dismissPopover:(NSNumber *)dataa
{ /* Dismiss you popover here and process data */
[popoverController dismissPopoverAnimated:YES];
NSLog(#"OLOLO");
}
Popover.h
#protocol DismissPopoverDelegate
- (void) dismissPopover:(NSNumber *)yourDataToTransfer;
#end
#interface SelectAgePopOver : UIViewController<UITableViewDataSource,
UITableViewDelegate,UIPopoverControllerDelegate>{
NSArray *items;
id<DismissPopoverDelegate> delegate;
}
#property (nonatomic, assign) id<DismissPopoverDelegate> delegate;
Popover.m
[self.delegate dismissPopover:selrow];
where i want the delegate called.
Thanks
the popover view is called by the following method in main view.m
controller = [[SelectAgePopOver alloc] initWithNibName:#"SelectAgePopOver" bundle:nil];
popoverController = [[UIPopoverController alloc] initWithContentViewController:controller];
[popoverController setDelegate:self];
popoverController.popoverContentSize = CGSizeMake(250, 294);
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
CGRect popRect = CGRectMake((self.AgeRangeTextField.frame.origin.x+50),
(self.AgeRangeTextField.frame.origin.y+50),
(self.AgeRangeTextField.frame.size.width),
(self.AgeRangeTextField.frame.size.height));
[popoverController presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
On where you instantiate the instance of the SelectAgePopOver, you need to set the delegate of the SelectAgePopOver instance to the MainScreen (self) in the Mainview.m, for example:
controller = [[SelectAgePopOver alloc] initWithNibName:#"SelectAgePopOver" bundle:nil];
;
controller.delegate = self;
Please try to set the controller delegate as shown above.
In the SelectAgePopOver.h class file, you do not need to set UIPopOverControllerDelegate though.

How do you programmatically call a viewcontroller get its view in the storyboard?

I am using a BookController class which is using pagenumbers to keep track of the current view. Currently I am creating each view controller on demand and writing the code programmatically. I would like to access the view controllers that I have created in the StoryBoard (the xib files) so that when I demand a new page it will access a Second view controller I have created.
// Provide a view controller on demand for the given page number
- (id) viewControllerForPage: (int) pageNumber
{
if ((pageNumber < 0) || (pageNumber > 31)) return nil;
if(pageNumber == 0){
//here is where I want to access the entire xib file that the SecondViewController is connected with
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
SecondViewController *myVC = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
myVC = [BookController rotatableViewController];
return myVC;
}
else if(pageNumber == 1){
// Establish a new controller
UIViewController *controller = [BookController rotatableViewController];
// Add a text view
UITextView *textview = [[UITextView alloc] initWithFrame:(CGRect){.size = CGSizeMake(100.0f,100.0f)}];
textview.text = [NSString stringWithFormat:#"This is dedicated to people"];
textview.font = [UIFont fontWithName:#"Futura" size:18.0f];
textview.center = CGPointMake(475.0f, 700.0f);
[controller.view addSubview:textview];
// Add a label
UILabel *textLabel = [[UILabel alloc] initWithFrame:(CGRect){.size = CGSizeMake(200.0f, 200.0f)}];
textLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
textLabel.text = [NSString stringWithFormat:#"1"];
textLabel.font = [UIFont fontWithName:#"Futura" size:18.0f];
textLabel.center = CGPointMake(475.0f, 985.0f);
[controller.view addSubview:textLabel];
// Add it as an image
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon#2x.png"]];
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageView.center = CGPointMake(160.0f, 230.0f);
[controller.view addSubview:imageView];
return controller;
}
Just not sure how to make a call to access that xib file i've created and make it into the first page (page=0). The second page (page =1) is an example of how i have drawn all the other pages in my book programmatically. Thanks!
Remember the Storyboard is just a collection of NIBs which simply instantiate the hierarchy of each view and connect the outlets to the owning view controllers. You do not want to instantiate the Storyboard yourself to just create a single view controller. What that is doing is creating new instances when the application has already been launched and is running with different instances. Even if you did have them wired up they would be wired to instances which are redundant and not the actual instances you want.
What I would do instead is create an individual NIB file for SecondViewController which you will use separately. Then you will need to wire it together. If this code is within the instance you need to access you would simply pass it along to a property on SecondViewController. Or maybe you just pass along values but most likely you will want to set a delegate property and define a protocol for SecondViewController to call back to the instance which created it.
For your code you can simply load the NIB with the following code.
SecondViewController *vc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
vc.delegate = self;
You just need to define that delegate and possibly any properties you need to give data to the newly created view controller.
Below is an example of a delegate setup which I recently created for a SideBar interface using a Storyboard. I have a container view for the Header VC which is in the Home VC. This Header VC could be like your SecondViewController because I could not connect it in the Storyboard so I did it with code. First I created a delegate property on the Header VC.
#protocol IFHeaderDelegate;
#interface IFHeaderViewController : UIViewController
#property (nonatomic, assign) IBOutlet id<IFHeaderDelegate> delegate;
#end
#protocol IFHeaderDelegate <NSObject>
- (void)headerViewDidToggleSideBar:(IFHeaderViewController *)sender;
#end
Then when a button is tapped I use the delegate for the callback. (Notice I use an NSAssert to verify the delegate is defined just to give me a heads up if I missed it.)
#import "IFHeaderViewController.h"
#interface IFHeaderViewController ()
#end
#implementation IFHeaderViewController
- (IBAction)siderBarButtonTapped:(id)sender {
NSAssert(self.delegate != nil, #"Delegate must be defined!");
if (self.delegate != nil) {
[self.delegate headerViewDidToggleSideBar:self];
}
}
#end
But in order to wire it up I had to set the delegate from the Home VC which I could not do from the Storyboard. What I did was set it in the Home VC when the embed segue was fired in prepareForSegue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DebugLog(#"segue.identifier: %#", segue.identifier);
if ([#"HomeHeader" isEqualToString:segue.identifier]) {
NSAssert([segue.destinationViewController isKindOfClass:[IFHeaderViewController class]], #"Destination VC must be the Header VC");
IFHeaderViewController *headerVC = (IFHeaderViewController *)segue.destinationViewController;
headerVC.delegate = self;
}
}
You can find the full project on GitHub: https://github.com/brennanMKE/Interfaces/tree/master/SideBar

popoverControllerDidDismissPopover method is not called

In my application I have a presentViewController, and inside it I have a button that opens a popover. In this popover I have a barButtonItem to save de data of this popover. I would like that when the user taps outside of the popover, the data could be saved too.
I've tried to use the popoverControllerDidDismissPopover method in the presentViewController view. I have the delegate but when I tap outside of the popover this method is not called.
What can I do?
Thanks!!
Add this line of code while adding popOver:
popover.delegate = self;
Also register popOverDelegate in .h file where u present your popOver COntroller
#interface yourViewController : UIViewController<UIPopoverControllerDelegate>
Please, pay attention to docs!
"Called on the delegate when the user has taken action to dismiss the popover.
This is not called when the popover is dismissed programmatically."
It was my case because my popover was closing on button tap with this method:
dismiss(animated: true, completion: nil)
You probably already solved it, but I just faced the same problem. I'm holding a instance of UIPopoverController in my Viewcontroller and had it this way:
self.popover.delegate = self;
self.popover = [[UIPopoverController alloc] initWithContentViewController:wgtvc];
of course this doesn't work because I'm initializing the UIPopoverController AFTER setting the delegate, which overrides the delegate setting. So the correct way is to FIRST initialize the UIPopovercontroller and THEN setting the delegate
self.popover = [[UIPopoverController alloc] initWithContentViewController:wgtvc];
self.popover.delegate = self;
Maybe you are reinitializing your UIPopoverController somewhere - just set the delegate again after reinitializing.
I had the same problem and I solved it by handling it different for iOS8.
Presentation code
UIViewController *searchViewController = [[UIViewController alloc] init];
[[searchViewController view] addSubview:_searchOptions];
[searchViewController setModalPresentationStyle:UIModalPresentationPopover];
[searchViewController setPreferredContentSize:CGSizeMake(500, 400)];
[_searchOptions setHidden:NO];
[_searchOptions setFrame:[[searchViewController view] bounds]];
[_searchOptions setAutoresizingMask:UIViewAutoresizingFlexibleWidthAndHeight];
if (CRIdiomToolsIsIOS8OrHigher())
{
UIPopoverPresentationController *popOverPresentationController = [searchViewController popoverPresentationController];
[popOverPresentationController setDelegate:self];
[popOverPresentationController setSourceView:[_searchOptionsButton disclosureView]];
[popOverPresentationController setSourceRect:[[_searchOptionsButton disclosureView] bounds]];
[self presentViewController:searchViewController animated:YES completion:nil];
}
else
{
UIPopoverController *popOverControler = [[UIPopoverController alloc] initWithContentViewController:searchViewController];
[popOverControler setDelegate:self];
[popOverControler setPopoverContentSize:CGSizeMake(500, 400)];
[popOverControler presentPopoverFromRect:[[_searchOptionsButton disclosureView] bounds] inView:[_searchOptionsButton disclosureView] permittedArrowDirections:UIPopoverArrowDirectionUp|UIPopoverArrowDirectionLeft animated:YES];
}
Delegate calls
#pragma mark Delegate Methods: UIPopoverControllerDelegate
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
[self showSearchOptions:NO animated:YES];
}
#pragma mark Delegate Methods: UIPopoverPresentationControllerDelegate
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
{
[self showSearchOptions:NO animated:YES];
}
I had the same issue. You will need to retain the popover object, that way the delegate method gets called. Its strange but it works.
#property (nonatomic, retain) UIPopoverController *popupObject;
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:viewController];
popup.delegate = self;
[popup presentPopoverFromRect:presentationRect inView:self permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
self.popupObject = popup; //Retained
-(void) popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
//Do whatever operation you need to perform
self.popupObject = nil;
}
I know this questions is old but hopefully it helps someone out there...
The issue is in the initialization of your popover controller. If you have established the popover segue in the storyboard you need to have a reference to this popover in order for the delegate to be called when it is dismissed.
In your prepare for segue method:
Instead of:
self.popoverController = [[UIPopoverController alloc]initWithContentViewController:segue.destinationViewController];
self.popoverController.delegate = self;
You need:
self.popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
self.popoverController.delegate = self;
Then make sure to correctly handle if the when the popover should appear in
(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender

UIPopoverController does not close

I have a normal UIPopoverController which is made in this way:
-(IBAction)btKBIs_click:(id)sender
{
if(kbiPopOver != NULL)
[kbiPopOver dismissPopoverAnimated:YES];
KBIViewController *kbiViewController = [[KBIViewController alloc]initWithNibName:#"KBIViewController" bundle:nil CurrentUser:currentUser];
kbiViewController.currentStatus = FIRST;
kbiViewController.firstlist = [currentUser getDescriptions];
kbiViewController.mapViewController =self;
UINavigationController* kbiNavController = [[UINavigationController alloc] initWithRootViewController:kbiViewController];
kbiPopOver = [[UIPopoverController alloc] initWithContentViewController:kbiNavController];
kbiPopOver.delegate = self;
kbiViewController.kbiPopOver = kbiPopOver;
[kbiPopOver presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionUp animated:true];
}
Inside the class KBIViewController I'm calling:
[self.kbiPopOver dismissPopoverAnimated:YES];
[self.kbiPopOver.delegate popoverControllerDidDismissPopover:self.kbiPopOver];
To dismiss it but it does not work. Why?
Did you add the <UIPopOverControllerDelegate> in your class interface and did you implement the – popoverControllerDidDismissPopover: method? Just call the dismissPopoverAnimated: explicitly in your code or in the delgate method, when you tap outside the popover. Remove that [self.kbiPopOver.delegate popoverControllerDidDismissPopover:self.kbiPopOver]; from your code.

Resources