UIPopoverController and release in delegate-method; "potential memory leak" - ios

I'm doing an alloc/init with my UIPopoverController, then release it in the delegate method. Whenever I perform a "build and analyze", I get memory warnings with "potential leaks" - am I doing something wrong or is there a way to get rid of those warnings?
Thanks a lot!
- (void) somewhere {
MyViewController *vc = [[MyViewController alloc] init];
UIPopoverController *popover=[[UIPopoverController alloc] initWithContentViewController:vc];
[vc release];
// show the popover
[popover presentPopoverFromRect:[cell frame] inView:self.tableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
popover.delegate = self;
}
- (void) popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
[popoverController release];
popoverController = nil;
}
EDIT: show complete somewhere-function

First of all, in the popoverControllerDidDismissPopover: method you should not release the popoverController instance, since it will be released by the framework.
Second, what's the meaning of that somewhere method? You should post the complete implementation here ... I suppose you are showing up the popover view, so you should do something like this:
- (void) somewhere {
// I suppose you have a local variable to hold the controller
_myPopover = [[UIPopoverController alloc] initWithContentViewController:vc];
_myPopover .delegate = self;
// ... do other things to configure the popover, if necessary
// I suppose you show it, with something like this
[_myPopover presentPopoverFromRect:yourRect inView:yourView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Then, when you no longer need the popover controller, you can release it. You could try with your code, this way:
- (void) popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
[_myPopover release];
_myPopover = nil;
}
This way you will always hold the instance of the popover where you need it, and release it when you have finished with it. In your previous implementation that instance was not bound to anything.

Related

Dismissing UIPopoverController with UINavigationController

I'm currently building an iPad app in which I need to implement a pop over view.
I have set up a view controller like I always do:
Create UIViewController wit xib file
set the xib up and do the necessary programming in it's .h & .m files
now in the view controller I'm loading it from (from a UIBarButtonItem), I have this code:
- (void) action
{
ItemContent *newItem = [[ItemContent alloc] initWithNibName:#"ItemContent" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:newItem];
_popover = [[UIPopoverController alloc] initWithContentViewController:nav];
[_popover setPopoverContentSize:CGSizeMake(557, 700) animated:YES];
_popover.delegate = self;
[_popover presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
This properly displays my view- and UINavigationController in a UIPopOverController. So far so good!
In the newItem view controller, I have made a bar button in my navigation bar that says "Done". When that button is pushed, I want the UIPopOverController to disappear. How do I do this:
Set a method for when te button is pushed. In this method I want to call a function on the view controller that loaded the Popover to dismiss it again.. but how do I do this?
Put things shortly
How do I make my UIPopOverController call a method on the view controller that loaded the UIPopOverController?
I have been searching SO for a while but none of the solutions and answers solve my problem. If I missed something please inform me ;)
Thank you so much in advance!
You can do this by delegate...
In NewItem.h declare a protocol
#protocol NewItemDelegate
-(void)onTapDoneButton;
#end
Now create a delegate property like this
#property (nonatomic, assign) id<NewItemDelegate>delegate;
In NewItem.m in doneButtonPuhsed method call this
[self.delegate onTapDoneButton];
Change this method a bit
- (void) action
{
ItemContent *newItem = [[ItemContent alloc] initWithNibName:#"ItemContent" bundle:nil];
newItem.delegate =self;
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:newItem];
_popover = [[UIPopoverController alloc] initWithContentViewController:nav];
[_popover setPopoverContentSize:CGSizeMake(557, 700) animated:YES];
_popover.delegate = self;
[_popover presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Now implement NewItemDelegate method below this action method.
-(void)onTapDoneButton{
//dismiss popover here
}
I had this problem too and solved it using notifications.
In your parent controller, in viewDidLoad method, you have to add an observer:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(closePopover)
name:#"closePopoverName"
object:nil];
Then, in your viewDidUnload method you remove the observer like this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Of course, you have to create the function which actually dismisses the popover:
- (void) closePopover
{
[_popover dismissPopoverAnimated:YES];
}
Then, in your ItemContent controller, you just post a notification when you want to close the popover:
[[NSNotificationCenter defaultCenter] postNotificationName:#"closePopoverName" object:self userInfo:nil];
You could define a protocol on ItemContent and use it on your CallerViewController. If you want to close your Popover, just call your delegate method, which you will implement on your CallerViewController

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

UIPopoverControllerDelegate methods never being called

This has me scratching my head. I have a view controller that implements UIPopoverControllerDelegate:
#interface MyViewController : UIViewController<UIPopoverControllerDelegate> {
It implements the methods in that protocol, like so:
- (bool)popoverControllerShouldDismissPopover
{
NSLog(#"THIS IS NEVER CALLED");
return true;
}
- (void)popoverControllerDidDismissPopover
{
NSLog(#"THIS IS ALSO NEVER CALLED");
}
I create the view controller to be shown in a popover, and the popover controller, like so:
-(IBAction)buttonPress:(id)sender
{
self.popoverViewController = [[MyPopoverViewController alloc] init];
self.popover = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
self.popover.delegate = self;
CGRect frame = button.frame;
[self.popover presentPopoverFromRect:frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
I'm very clearly setting popover.delegate = self. HOWEVER, the popoverViewController delegate methods I've implemented are never being called.
Any ideas?
Edit: Note, I'm using ARC & LLVM.
I think your delegate method implementations are incorrect. Try
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
rather than
- (bool)popoverControllerShouldDismissPopover
and
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
rather than
- (void)popoverControllerDidDismissPopover
it's important that you get the method names and parameters correct, otherwise they will not be called.
Good luck!

UIPopoverController deallocated issue

I used a Popover to display image in it. When the user touch a button, the popover appears with a slideshow inside.
I initialize the Popover like this : `
- (IBAction)showPopover:(UIButton *)sender {
myPopover *content = [[myPopover alloc] init];
detailViewPopover = [[UIPopoverController alloc] initWithContentViewController:content];
detailViewPopover.popoverContentSize = CGSizeMake(600., 400.);
detailViewPopover.delegate = self;
[detailViewPopover presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[content release];
}
`
detailViewPopover is a UIPopoverController, I declare it my .h.
I dismiss the Popover like this : `
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// If a popover is dismissed, set the last button tapped to nil.
[popoverController release];
}`
When I run my app, it works until I got "-[UIPopoverController release]: message sent to deallocated instance 0x1b29b0" and my apps crashes...
I understand I release too much time my UIPopoverController, but I don't know where. Is my implementation good ?
Thanks for your help
Let me know if you need more information, I will edit the post
You shouldn't release your popoverController here.
You need to call release on detailViewPopover in your current view controllers dealloc method
- (void) dealloc
{
[detailViewPopover release];
[super dealloc];
}

Dismissing iPad UIPopoverController from within its content controller

So I have a popover with a button in it. When that button is pushed, I want the popover to go away. It seems easy enough, but I can't figure it out for the life of me. The code I use to show the popover is below:
AddCategoryViewController* content = [[AddCategoryViewController alloc] init];
UIPopoverController* aPopover = [[UIPopoverController alloc]
initWithContentViewController:content];
aPopover.delegate = self;
[content release];
// Store the popover in a custom property for later use.
self.addCategoryPopover = aPopover;
[aPopover release];
[addCategoryPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
Within the addcategoryviewcontroller, I have:
-(IBAction)saveAddCategory:(id)sender {
if (rootViewController == nil)
rootViewController = [[RootViewController alloc] init];
[rootViewController.addCategoryPopover dismissPopoverAnimated:YES];
[rootViewController dismissPopover];
}
Rootviewcontroller is where the popover is being created from. Unfortunately, neither of those methods work to dismiss it. any help?
You would be seeing a warning at this line.
aPopover.delegate = self;
and if you would execute your code. The app would crash. Instead you need to do it like this.
I have
- (void)viewWillDisappear:(BOOL)anAnimated
{
[self.dPopover dismissPopoverAnimated: NO];
self.dPopover = nil;
[super viewWillDisappear: anAnimated];
}
and don't see why this wouldn't work in your case.
Your if is a bit troubling, so my guess is you aren't talking to the view you think you are. rootViewController.addCategoryPopover is probably nil, because you made a new controller.
I think I answered just a similar question with the solution I used to dismiss a popover with a UIView loaded from a MKMapView.
The use of my solution is basically the same as for any other view loading a popover.
Have a look at:
How to dismissPopoverAnimated on iPad with UIPopoverController in MKMapView (SDK3.2). I hope that solved your problem.
use NSNotificationCenter To DissmissPoperController Fro Father viewControll

Resources