UIPopover with UINavigationController and UITableView: tableView delegates not called - ios

I am trying to display a simple iPad popover which contains a navigationController with a tableView.
popover -> navigation controller -> view controller -> table view.
I do need the navigationController because on touching the cells I want to push another viewController (within that same popover).
Without the navigation controller, everything is fine.
But as soon as I put the viewController inside a navigationController, the tableView stops responding (didSelectRow doesn't get called). I suppose something is wrong with my delegates but I just can't work it out.
. The navigationController responds fine (I can hit a button I have in the top bar)
. The buttons that are IN the cells respond fine.
. If I touch down and hold on a cell it gets highlighted, but not selected.
UPDATE: I just found out that if I hold the cell down for at least a second, the delegate is called when I release it. any less than that and it is never called...???
Here is the code use:
ModalViewController* controllerWithTable = [[self storyboard] instantiateViewControllerWithIdentifier:identifier];
UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:controllerWithTable];
UIPopoverController* popover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
popover.delegate = self;
[popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

If you are using a popoverController to show a table view, you don't need to embed it in a navigation Controller, Instead make a different Viewcontroller with the table view and just shoe that inside a popover controller .I used it somewhat like this..
Make a global reference for UIPopoverController in your app delegate,
//in your Appdelegate.h file declare this
#property(strong, nonatomic) UIPopoverController *popOverForTableView;
Now In the controller which you want to show the PopOver view use this,
TableViewCOntroller* popoverContent = [[TableViewCOntroller alloc] init];
NSString *identifier=#"tableVC"
popoverContent =[[UIStoryboard storyboardWithName:#"Main"
bundle:nil]
instantiateViewControllerWithIdentifier:identifier];
popoverContent.preferredContentSize = CGSizeMake(330, 280);
AppDelegate *appDelegate=(AppDelegate *)[[UIApplication sharedApplication]delegate];
appDelegate. popOverForTableView = [[UIPopoverController alloc]initWithContentViewController:popoverContent];
appDelegate.popOverForTableView.delegate = self;
appDelegate.popOverForTableView.backgroundColor=[UIColor blackColor];
[appDelegate.popOverForTableView presentPopoverFromRect:self.date.frame inView:self.view permittedArrowDirections:(UIPopoverArrowDirectionUp) animated:YES];
You can dismiss it accordingly…,…see if this Helps..

Ok I found the answer there: https://stackoverflow.com/a/18159463/3562952
The tableView was not irresponsive, it was deceptively responding only after a 1-3 seconds hold down.
I had a tap responder on the parent view that was capturing the tap. I am now removing it when displaying the popover and putting back in on dismissal.
I was googling for the wrong symptoms :)

Related

Getting warning message while using PopoverController on iPad

I have two view controllers – AViewController and BViewController. BViewController's view is used for AViewController's subview:
BViewController *bViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"basic"];
[self.view addSubview: bViewController.view];
...so that I can display BViewController's data on AViewController but handle data in BViewController. In BViewController I use a UIPopOverController when I press some button on it, displaying it like this:
_popOverController = [[UIPopoverController alloc] initWithContentViewController:_popContentView];
[_popOverController presentPopoverFromRect:sender.frame inView:sender.superview permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
I'm getting this warning message:
presenting view controllers on detached view controllers is discouraged
How can I resolve this problem?
Since you are showing UIPopoverController in a subview . Show UIPopoverController in viewcontroller .

Best way to use navigation controller for uipopoverview

I want to push to another view from a popoverview. For that purpose I had a taken navigation controller to that popover. And also its working fine.
The problem occurs in the second view. To allow the user to send an email i show a mail composer. But i am getting two navigation controllers.
Here is the code for the first popoverview:
SettingsVC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SettingsVC"];
vc.delegate = self;
UINavigationController *naviCon = [[UINavigationController alloc]initWithRootViewController:vc];
self.settingsPopover = [[UIPopoverController alloc] initWithContentViewController:naviCon];
CGRect frame = CGRectMake(974.f, 36.f, 0, 0);
self.settingsPopover.popoverContentSize = CGSizeMake(300, 250);
[self.settingsPopover presentPopoverFromRect:frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
When I needed something similar, I called the MFMailComposeViewController from the ViewController which calls the PopoverController (the parent ViewController) and also included the delegate ect in that ViewController.
I defined a protocol in the ContentViewController of the PopoverViewController which informs the parent ViewController when it needs to call the MFMailComposeViewController.
All worked perfectly without a problem... hope that helps

iOS view controller memory not released after it's been dismissed

When the user clicks a button it presents a new tab bar view controller with two view controllers. Here's how I do that
ACLevelDownloadController *dvc = [[ACLevelDownloadController alloc] initWithNibName:#"ACLevelDownloadController" bundle:[NSBundle mainBundle]];
ACInstalledLevelsController *ivc = [[ACInstalledLevelsController alloc] initWithNibName:#"ACInstalledLevelsController" bundle:[NSBundle mainBundle]];
UITabBarController *control = [[UITabBarController alloc] init];
control.viewControllers = #[dvc, ivc];
dvc.tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemFeatured tag:0];
ivc.tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemDownloads tag:1];
[self presentViewController:control animated:YES completion:nil];
this works fine. I dismiss that view controller with a dismiss method in both the ACLevelDownloadController and ACInstalledLevelsController. That also works fine. What's strange is that the memory usage goes up when I present the view controller
but it never goes back down. If I present it again, it goes up even more
I'm using ARC. Why is the memory that the view controllers use not being released after they are dismissed?
EDIT
The way they are dismissed is both ACLevelDownloadController and ACInstalledLevelsController have IBActions hooked up that call this method when they are clicked
- (void)dismiss:(id)sender{
[self dismissViewControllerAnimated:YES completion:nil];
}
What we can observe from the memory usage graph is that the tabViewController is not being dismissed properly and it builds up in the stack. While dismissing you have to allow the viewController which presented the tabViewController to dismiss it. It is its responsibility to dismiss. Also keep weak references for Outlets and assign any strong references to nil** in viewWillDisapper: . You can present a viewController modally as a temporary interruption to obtain important information from the user. If its not the case here, you can remove presenting modally. Check this link. Hope this helps :)

UINavigationController with UITabViewController

I'm building an app which's delegate has a UINavigationController (navigationController). The first view is a UITabViewController (tabView) which has a UINavigationController with a UIViewController with a UITableView which shows some contacts.
What I want to do is to push a new viewcontroller with the contact's info when tapping over a contact in the tableview (over the toppest navController)
I do the following in the appDelegate:
[self.window makeKeyAndVisible];
[self.window addSubview:[navigationController view]];
TabsView *tabsView = [[TabsView alloc] initWithNibName:nil bundle:nil];
[navigationController.view addSubview:[tabsView view]];
tabsView's first tab loads ContactsView.m which has a UINavigationController with all contacts and when someone clicks on one row, it is supposed to push the new view as this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[table deselectRowAtIndexPath:indexPath animated:YES];
ContactSecondView * varContactSecondView = [[ContactSecondView alloc] initWithNibName:nil bundle:nil];
varContactSecondView.title = [[contactsArray objectAtIndex:indexPath.row] name];
[self.navigationController pushViewController:varContactSecondView animated:YES];
[varContactMapView release];
}
But nothing happens when touching in a row.
So I have different files: Delegate with UINavigationController <- UITabViewController <- UIViewController with UINavigationController with UITableView; and I want to push a ViewController into the first navigationcontroller.
How is supposed to access to delegate's navigationController? Am I doing it right?
Edit: If this gives any clue, when I do self.navigationController.title = #"Contacts"; in ContactsView.m, it's not changing the title of the topbar.
Thanks!
Two things.
It is not recommended to embed a UITabBarController in a navigation controller. It is ok to embed a UINavigationController within a UITabBarController. I know it would be a "nice to have" to embed your UITabBarController in the UINavigationController, but you may want to rethink your design so that you follow the iOS design philosophy.
Instead of adding the subview to the window in your appDelegate, try adding which ever controller you are using to the window's rootViewController property i.e,
self.window.rootViewController=navigationController;
I may be wrong, but I think you don't use the correct way to set your view controller in your navigation controller.
You do :
[navigationController.view addSubview:[tabsView view]];
I would use :
[navigationController setViewControllers:[NSArray arrayWithObject:tabsView] animated:NO];

Landscape UISplitViewController when using a UINavigationController in the detail

I am developing an iPad/Universal application, and I am facing the problem of handling a UINavigationController as the main detail view in a UISplitViewController. What I want to know is how to add the default side controller button to the detail controller when in landscape orientation.
Definition
The split view controller has been defined this way:
splitViewController = [[UISplitViewController alloc] init];
SideController *root = [[[SideController alloc] init] autorelease];
DetailController *detail = [[DetailController alloc] init];
InserisciDatiController *calcolo = [[[InserisciDatiController alloc]
initWithNibName:#"InserisciDatiNuovi"
bundle:[NSBundle mainBundle]]
autorelease];
UINavigationController *rootNav = [[[UINavigationController alloc] initWithRootViewController:root]autorelease];
UINavigationController *calcoloNav = [[[UINavigationController alloc] initWithRootViewController:calcolo] autorelease];
splitViewController.viewControllers = [NSArray arrayWithObjects:rootNav, calcoloNav, nil];
splitViewController.delegate = detail;
and later on I release all the releasable objects.
I am using the SideController as a sort of index for the detail controller. It has a table view, and clicking each row I update the main view controller of the detail. Each new controller is always an instance of UINavigationController.
Update the detail
myAppDelegate *delegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *nav = (UINavigationController *)[delegate.splitViewController.viewControllers objectAtIndex:1];
[nav setViewControllers:[NSArray arrayWithObjects:controller, nil]];
I use this piece of code to update the detail controller, when the user taps a row in the side view controller.
Handle landscape orientation
I'd like to know how to handle the landscape orientation, when I want to add the default toolbar button to display the hidden side view controller. What I am not able to do is getting the toolbar of the detail navigation controller to add the button using this method:
- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc
And also, when I push a new controller to the navigation controller the default back button will appear in the toolbar. In this case how should I handle the button creation?
Update
Please, do not tell me that no-one has ever had this kind of problem! How do you develop iPad apps? Sob ...
I found a way that could be useful for someone, even though I do not really think this is a clean way of handling the navigation controller.
In the split view controller delegate I implemented the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: method this way:
- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc
{
barButtonItem.title = NSLocalizedString(#"menu", nil);
myAppDelegate *app = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
UINavigationController *nav = [app.splitViewController.viewControllers objectAtIndex:1];
UIViewController *ctrl = [nav.viewControllers objectAtIndex:0];
if (!ctrl.navigationItem.backBarButtonItem && !ctrl.navigationItem.leftBarButtonItem) {
ctrl.navigationItem.leftBarButtonItem = barButtonItem;
}
}
Here I present the bar button item that will show the popover view representing the side view controller if and only if the navigation controller is not showing the back button or another custom left button item.
Hope this helps someone!
I believe that Slava Bushtruk of Alterplay has worked out what you're looking for and used it in his APSplitViewController library.
I think the reason you haven't gotten any good answers is that it's really hard to understand your problem, i.e., your question could be clearer.
So first let me see if I've understood the problem correctly. Is the problem that you don't know how to handle the case when you've pushed something on your navigation controller and is supposed to show both the back button and the split view button?
If so, the way we've solved that problem is that the split view button is only visible in the root of the navigation controller. The side controller is usually only relevant for the detail view's root view controller anyway.
If I've misunderstood your problem or my solution isn't applicable to your project, please let me know.
EDIT: So if you insist on doing this, here's a way to do it:
toolbar = [[UIToolbar alloc] initWithFrame:(UIInterfaceOrientationIsPortrait(interfaceOrientation)) ? CGRectMake(0, 0, 768, 44) : CGRectMake(0, 0, 703, 44)];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self.navigationController.navigationBar addSubview:toolbar];
On viewWillDisappear:
[self setToolbarHidden:YES animated:animated];
and on viewWillAppear:
[self setToolbarHidden:NO animated:animated];
Now you have a toolbar that you can add anything to. Well, anything that can be added to a UIToolbar anyway, which is almost anything.

Resources