I'm trying to make my application grab a photo from the user's Photo library using UIImagePickerController and display it in the app. My code works great for the iPhone, but I need to use UIPopoverController for the iPad. I'm still very new to programming in general, so I'm having a really difficult time trying to figure out how to do this. While testing it out, I ran into a strange error. The debugger says "Terminating app due to uncaught exception 'NSGenericException', reason: '-[UIPopoverController dealloc] reached while popover is still visible." but I don't dealloc anything, I have ARC turned on. Here is my code:
ViewController.m:
#import "PhotoViewController.h"
#implementation PhotoViewController
#synthesize grabButton;
#synthesize image;
#synthesize imgPicker;
- (IBAction)grabImage {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[popover presentPopoverFromRect:self.image.bounds inView:self.image permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentModalViewController:imgPicker animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
image.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
- (void)viewDidLoad
{
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsImageEditing = YES;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
Any help is much appreciated! Thank you!
Ray Wenderlich has a nice tutorial on UIPopoverControllers here: http://www.raywenderlich.com/1056/ipad-for-iphone-developers-101-uipopovercontroller-tutorial
Related
I have a viewcontroller called via UIStoryboardPopoverSegue and inside there is a button to call the imagePickerController, it's ok for the first call but the second time it crash.
The code is use is ok when it is not through UIStoryboardPopoverSegue.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image=[info objectForKey:UIImagePickerControllerOriginalImage];
UIImageWriteToSavedPhotosAlbum (image, nil, nil , nil);
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)takephoto:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.delegate=self;
self.imagePicker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentViewController:imagePicker animated:YES completion:nil];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (!self.imagePicker)
{
self.imagePicker = [[UIImagePickerController alloc] init];
}
}
I enabled NSZobmbie to show any log that can help me tracing it.
* -[UIImagePickerController isKindOfClass:]: message sent to
deallocated instance 0x1eb3b700
Your UIImagePickerController is released and then attempted to be accessed later - so crashes!
To fix it, make the UIImagePickerController a strongly referenced property of the owning instance:
#property (strong, nonatomic) UIImagePickerController *imagePicker;
initialise it once:
if (!self.imagePicker) self.imagePicker = [[UIImagePickerController alloc] init];
and use:
[self.imagePicker doStuff]
for access.
That should solve it.
EDIT
if ([[segue identifier]isEqualToString:#"tcwindshield"]) {
self.ips = [segue destinationViewController];
self.ips.delegate = self
self.ips.strStatValue=#"WindShield";
}
Whilst I understand why im receiving an error
'', reason: '-[UIPopoverController initWithContentViewController:] called when not running under UIUserInterfaceIdiomPad.'
Rectifying it is becoming a bit tricky. My pop over is only required on the ipad and not on the iphone version. I omitted any code for the iphones if statement and still got a crash. . Presuming that I must call a view on iphone as well as its a universal app, I simply called the nib in the if iphone statement, and that didn't work either.
- (IBAction)popZs:(id)sender {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
[self->popoverController setPopoverContentSize: CGSizeMake(601, 571)];
[popoverController presentPopoverFromRect:((UIButton *)sender).bounds
inView:sender
permittedArrowDirections:UIPopoverArrowDirectionUp
animated:YES];
}
}
else {
/////using iPhone/////not sure how to handle this spart
zsTablePop *pop = [[zsTablePop alloc] init];
pop.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[pop presentModalViewController:pop animated:YES];
}
Keep getting same erorr even though im using if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
creation of pop over
.m
#import "ICCircuitDetails.h"
#import "zsTablePop.h" ///////////////pop over xib/////
#interface ICCircuitDetails ()
{
zsTablePop *controller;
UIPopoverController *popoverController;
}
///////more code/////////////
- (id)initWithCircuit:(Circuit *)circuit
{
self = [super initWithCertificate:circuit.distributionBoard.certificate];
if (self) {
self.circuit = circuit;
[[NSBundle mainBundle] loadNibNamed:#"ICCircuitDetails" owner:self options:nil];
self.view.contentSize = CGSizeMake(self.contentView.frame.size.width, self.contentView.frame.size.height);
///////////other code here/////////////////
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
controller = [[zsTablePop alloc] initWithNibName:#"zsTablePop" bundle:nil];
popoverController = [[UIPopoverController alloc] initWithContentViewController:controller];
Your error message says you try to instantiate a popover. The code only is about presenting it. You need to handle the instantiation as well.
I have an universal app that allows to select an image from the device photo library for later manipulation, the code works fine on the iPad but nothing happens on the iPhone, not even the cancel button and after an image is selected nothing happens neither here is my code:
-(IBAction)grabImage:(id)sender
{
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
imgPicker = [[UIImagePickerController alloc] init];
[imgPicker setDelegate:self];
popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[popover setDelegate:self];
CGPoint position = [view1.superview convertPoint:view1.frame.origin toView:nil];
CGRect popOverFrame = CGRectMake( position.x, position.y, self.view.frame.size.width, self.view.frame.size.height );
[popover presentPopoverFromRect:popOverFrame inView:self.view permittedArrowDirections:nil animated:NO];
[popover setPopoverContentSize:CGSizeMake(320, 480)];
[imgPicker release];
}
else
{
imgPicker = [[UIImagePickerController alloc] init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:self.imgPicker animated:YES];
[imgPicker release];
}
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
CGImageRef imgRef = pickedImage.CGImage;
app->setImage( pickedImage, CGImageGetWidth(imgRef), CGImageGetHeight(imgRef) );
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
// Enable texture siwth after an image has been loaded
[textureSwitch setEnabled:YES];
[textureSwitch setOn:YES];
app->isTextureDrawingOn = [textureSwitch isOn];
[fillsSwitch setOn:NO];
app->isFillsDrawingOn = [fillsSwitch isOn];
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
[popover dismissPopoverAnimated:YES];
}
ofLog(OF_LOG_VERBOSE, "cancel after selection");
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
[popover dismissPopoverAnimated:YES];
}
ofLog(OF_LOG_VERBOSE, "did cancel");
}
Instead of using below code.
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
Try this code
[self dismissModalViewControllerAnimated:YES];
and also check did you add UIImagePickerControllerDelegate in your interface file.
SOLUTION: (From my comment)
Try this [self.imgPicker dismissModalViewControllerAnimated:YES];
This will work.
For iOS 7: To dismiss a present view controller
[self.imgPicker dismissViewControllerAnimated: YES completion: NULL];
Add UIImagePickerControllerDelegate in your interface file
and then implement this code in your .m file
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissModalViewControllerAnimated:YES];
}
i hope it's solve your problem.
check viewWillAppear or viewDidAppear methods of your parent controller which calls the picker. On iPhone this methods will be called after picker view disappeared. They will not be called after popover disappeared on iPad. I just found error in my code where i set nil to ivar for picked image in viewWillAppear. it take me two days to understand what is happened ;)
Good luck!
An easiest solution:
Add UIImagePickerControllerDelegate in your interface file
and then implement this code in your .m file
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissViewControllerAnimated:YES completion:nil];
}
Swift 3.0
Thanks to MBH this worked for me in my Xcode 8 and iOS 10 project:
internal func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
dismiss(animated: true, completion: nil)
}
For closing it in Swift:
After adding those protocols to you ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate
internal func imagePickerControllerDidCancel(picker: UIImagePickerController){
dismissViewControllerAnimated(true, completion: nil)
}
I'm trying to use UIImagePickerController to grab a photo from the users Photos on their iPhone / iPad. This code works just fine for iPhone, but when I run it on iPad, the debugger gives me the message "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'On iPad, UIImagePickerController must be presented via UIPopoverController'". I'm very new to Objective-C, so I'm unsure of how to edit this code to use UIPopoverController when its being run on the iPad. I'd rather not create 2 new View Controllers, so I was wondering if someone knows what code I would need to add in to have it work on both the iPhone and iPad. Here is the code in my view controllers:
ViewController.h:
#interface PhotoViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate> {
UIButton *grabButton;
UIImageView *image;
UIImagePickerController *imgPicker;
}
#property (strong, nonatomic) IBOutlet UIButton *grabButton;
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (strong, nonatomic) UIImagePickerController *imgPicker;
- (IBAction)grabImage;
#end
ViewController.m:
#import "PhotoViewController.h"
#implementation PhotoViewController
#synthesize grabButton;
#synthesize image;
#synthesize imgPicker;
- (IBAction)grabImage {
[self presentModalViewController:self.imgPicker animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
image.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Photo Gallery", #"Photo Gallery");
self.tabBarItem.image = [UIImage imageNamed:#"42-photos.png"];
}
return self;
}
- (void)viewDidLoad
{
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsImageEditing = YES;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[super viewDidLoad];
}
Thanks in advance!
You have the answer through that error message !
Use UIPopOverController with UIImagePicker for iPad.
If you want to know how to use UIPopOverController, you can look at this tutorial !
Another youtube tutorial - http://www.youtube.com/watch?v=6Gc3kxVwfmE
Like Legolas mentioned, in an iPad app you must use a UIPopOverController in order to present an imagePicker. I'm usually not a fan of having any code in my app that performs tasks based on device type, but if you don't find a better solution you can do the following.
if ([[UIDevice currentDevice].model isEqual:#"iPad"])
{
// Display image picker in a popover
}
else
{
// display imagePicker as a modal
}
Check the documentation for device models:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html
It's worked for me. Please try below code
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:self.imgpicker];
popover.delegate =self;
[popover presentPopoverFromRect:self.view.bounds inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];}else{
[self presentModalViewController:self.imgpicker animated:YES];
}
I'm trying to use UIImagePickerController to grab a photo from the users Photos on their iPhone / iPad. This code works just fine for iPhone, but when I run it on iPad, the debugger gives me the message "Terminating app due to uncaught exception 'NSGenericException', reason: '-[UIPopoverController dealloc] reached while popover is still visible.". I'm very new to Objective-C, so I'm unsure of whats causing this, I do not dealloc anything and I have ARC turned on. Here is my code:
ViewController.m
#import "PhotoViewController.h"
#implementation PhotoViewController
#synthesize grabButton;
#synthesize image;
#synthesize imgPicker;
- (IBAction)grabImage {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[popover presentPopoverFromRect:self.image.bounds inView:self.image permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentModalViewController:imgPicker animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
image.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
- (void)viewDidLoad
{
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsImageEditing = YES;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
UIPopover is an ugly patchwork beast of an object. It must be a strong property and an iVar to ensure that Dealloc isn't reached prematurely. Add this in the .h Like so:
#interface MyClass: NSObject {
UIPopover *_popover;
}
#property (nonatomic, strong) UIPopover * popover;
//.m
#synthesize popover = _popover;
When you instantiate the popover, assign it to either the property or the instance:
self.popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
or
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];