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];
}
Related
I want to display the modalViewController from the 2nd screen of the app, and when I dismiss the controller it should navigate to the 1st screen. The below code works fine in iPhone 4, 5 and iPod Touch but NOT in iPAD. The objective is when I dismiss the modalViewController it shouldn't go back to the second screen, but it should display the first screen.
ShareEmail *shareEmail = [[ShareEmail alloc] initWithNibName:[NSString stringWithFormat:#"%#",xibShareEmail] bundle:nil];
shareEmail.fromWer = #"ownPer";
[self presentModalViewController:shareEmail animated:NO];
[shareEmail release];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
In share email class
[self dismissModalViewControllerAnimated:YES];
You need to retain your shareEmail view controller - make a synthesized retained property
YourClass.h:
#property (nonatomic, retain) ShareEmail *shareEmailViewController;
YourClass.m:
#synthesize shareEmailViewController;
Then display your modal view controller by:
ShareEmail *shareEmail = [[ShareEmail alloc] initWithNibName:[NSString stringWithFormat:#"%#",xibShareEmail] bundle:nil];
self.shareEmailViewController = shareEmail;
[self presentModalViewController:shareEmail animated:NO];
[shareEmail release];
The retained property will keep the view controller from being deallocated while in use. Then when you dismiss it later you can do:
[self.shareEmailViewController dismissModalViewControllerAnimated:YES];
self.shareEmailViewController = nil;
which will release the retained property and free the memory after you're done with it.
Something interesting is happening. You are presenting a view controller from self, and then you're having the navigationController perform its backwards navigation. At this point, the self I was talking about earlier disappears.
Remove the popViewController method from your presentViewController method.
Also, you'll need to use the ^completion handler method. That's where you should put your navigation controller pop code.
-(void)present {
ShareEmail *email = [[ShareEmail...
//You'll need to get a weak reference to `self` in `email`
email.modalDelegate = self; //you need to make a property in ShareEmail
[self presentViewController:email animated:YES completion:nil];
[email release];
}
-(void)dismiss {
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
}
//in ShareEmail.m
[modalDelegate dismiss];
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
I am using a class inherited from UINavigationController present as a modal view, in the navigation bar I have a button 'Done' which will dismiss the modal view when user tap on it. Everything behave normal except the dealloc() in ImagePickerController, GroupPickerController (which is initialized as root view) not get called when I dismiss the modal view. This cause the leak of the memory.
Here is the code use it:
ImagePickerController *picker = [[ImagePickerController alloc] initWithRootViewController:nil];
// don't show animation since this may cause the screen flash with white background.
[self presentModalViewController:picker animated:NO];
picker.navigationBar.barStyle = UIBarStyleBlack;
[picker release];
Here is what's inside ImagePickerController, which is a UINavigationController:
- (id)initWithRootViewController:(UIViewController *)root {
GroupPickerController *controller = [[GroupPickerController alloc] initWithNibName:nil bundle:nil];
self = [super initWithRootViewController:controller];
[controller release];
if (self) {
self.modalPresentationStyle = UIModalPresentationPageSheet;
}
return self;
}
- (void)dealloc {
[super dealloc];
}
-(void) dismiss
{
[self.navigationController setViewControllers:nil];
[self dismissModalViewControllerAnimated:YES];
}
Here is the code in GroupPickerController, it response to a button in the navigation bar, to dismiss the modal view:
...
#pragma mark - button actions
- (void)done {
[self.parent dismiss];
}
I tried to manually remove the views from NavigationController, seemed not no effect at all...
[self.navigationController setViewControllers:nil];
Thanks for the help!
UPDATED:
Please disregard this question, apparently it's a mistake. :(
Finally get the problem solved... not change any of the code, but a rebuild the project. :(
First of all, you should not be subclassing UINavigationController:
This class is not intended for subclassing.
What does this line do?
controller.parent = self;
If the controller retains the parent-property, you have a retain cycle which would cause the issue you are describing. Remember that all view controllers in the UINavigationController stack can access the navigation controller with the -navigationController property.
There's is a difference between a UIViewController begin dismissed and released.
When you dismiss it, it can be released at any moment, but not necessarily immediately.
Are you sure you have a memory leak ? Maybe the picker is released a few seconds after the dimiss.
If you really have a memory leak, that means there is another place where you picker is retained.
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.
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