Using ImagePickerController causes my app to crash - ios

I researched a lot on this one. On touching an button, I have to pick an image from device and display on the screen.
But it causes my app to crash when button is touched/pressed.
It crashes from this line of code:
[self presentModalViewController:myPhotopicker animated:YES];
I am developing an iPad app using Xcode 4.2. I am using iPad 5.0 simulator for testing. And my system runs on Mac OS X, version 10.6.8.
Following function is called when button is pressed:
-(IBAction)getPhoto:(id)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
if (myPhotopicker==nil) { myPhotopicker = [[UIImagePickerController alloc] init];
myPhotopicker.delegate = self; }// create once!
myPhotopicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:myPhotopicker animated:YES];
} else {
NSString *str = #"Photo Album is not available!";
}
}

I tried your code and can reproduce the crash in the simulator.
But it is working fine on my iPhone 4 with iOS 4.2.
That said, I made my gallery in the simulator contain some photos.
(Start in-simulator Safari, open some page, save some pictures by long pressing on them and choosing save from the menu.)
Now, the simulator writes
2012-05-08 15:53:55.605 test[5870:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'On iPad, UIImagePickerController must be presented via UIPopoverController'
to the console.
Okay, read, done:
-(IBAction)getPhoto:(UIButton *)sender
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
if (myPhotopicker==nil) {
myPhotopicker = [[UIImagePickerController alloc] init];
myPhotopicker.delegate = self;
}// create once!
myPhotopicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad Code:
UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:myPhotopicker];
[popover presentPopoverFromRect:sender.bounds
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
} else {
// iPhone Code:
[self presentModalViewController:myPhotopicker animated:YES];
}
} else {
NSLog(#"Photo Album is not available!");
}
}
And now it looks like that:

Related

iOS 13: MPMediaPickerController - Internal Error / The requested app extension could not be found

It seems that the general MPMediaPicker is not working anymore on ios13 (ipad air 2, iphone SE)
The example 1:1 copied from there is not showing up the media picker
https://developer.apple.com/documentation/mediaplayer/displaying_a_media_picker_from_your_app
Any tips how to get back functionality??
Note 1
When using using the MPMediaPickerController like this
musicPickerView = [[UIView alloc] initWithFrame:fullScreenRect];
musicPickerView.alpha = 0.0f;
musicPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
musicPicker.showsCloudItems = false;
musicPicker.showsItemsWithProtectedAssets = false;
musicPicker.delegate = self;
musicPicker.allowsPickingMultipleItems = false;
musicPicker.prompt = NSLocalizedString(#"Select a song", #"Select a song");
musicPicker.view.frame = musicPickerView.bounds;
[self addChildViewController:musicPicker];
[musicPickerView addSubview:musicPicker.view];
[self.view addSubview:musicPickerView];
[musicPicker didMoveToParentViewController:self];
[self fadeInMusicPicker:true];
The delegate is not invoked at all. No log is shown, only the native alert.
I am getting this native altert
Internal Error
The requested app extension could not be found
[Cancel]
Note 2
It seems to be the issue when the apple music app is not installed on that device. Does anybody know a reliable way to find out if apple music app is installed?
It seems that the Music app from apple has to be installed on that device. Still not 100% reproducible, but with that app installed, I never saw that issue again.
did you set the permission for the Media Library in your info.plist?
NSAppleMusicUsageDescription
From iOS 13 MPMediaPicker required user authorization, unlike the earlier iOS version. So you need to handle the authentication first and then show the picker if user granted the permission. You code will be as follow,
MPMediaLibraryAuthorizationStatus authorizationStatus = MPMediaLibrary.authorizationStatus;
switch (authorizationStatus)
{
case MPMediaLibraryAuthorizationStatusAuthorized:
{
[self showPickerView];
break;
}
case MPMediaLibraryAuthorizationStatusNotDetermined:
{
// Not yet authorized - request it from the system
[MPMediaLibrary requestAuthorization:^(MPMediaLibraryAuthorizationStatus authorizationStatus)
{
if ( authorizationStatus == MPMediaLibraryAuthorizationStatusAuthorized )
{
dispatch_async(dispatch_get_main_queue(), ^{
[self showPickerView];
});
}
else
{
PLog(#"The Media Library was not authorized by the user");
}
}];
break;
}
case MPMediaLibraryAuthorizationStatusRestricted:
case MPMediaLibraryAuthorizationStatusDenied:
{
// user has previously denied access. Ask again with our own alert that is similar to the system alert
// then take them to the System Settings so they can turn it on for the app
break;
}
}
-(void)showPickerView
{
musicPickerView = [[UIView alloc] initWithFrame:fullScreenRect];
musicPickerView.alpha = 0.0f;
musicPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
musicPicker.showsCloudItems = false;
musicPicker.showsItemsWithProtectedAssets = false;
musicPicker.delegate = self;
musicPicker.allowsPickingMultipleItems = false;
musicPicker.prompt = NSLocalizedString(#"Select a song", #"Select a song");
musicPicker.view.frame = musicPickerView.bounds;
[self addChildViewController:musicPicker];
[musicPickerView addSubview:musicPicker.view];
[self.view addSubview:musicPickerView];
[musicPicker didMoveToParentViewController:self];
[self fadeInMusicPicker:true];
}

ABPeoplePickerNavigationController and UIImagePickerController not displaying correctly on ipad iOS7

When I try use "ABPeoplePickerNavigationController" or "UIImagePickerController", in most cases it won't load up correctly. It will show part of the screen (transparent) starting in the middle of the screen in iOS 7 (ipad) for both simulator and device (screenshot below). In iOS 8 everything works correctly.
This is the code I use for ABPeoplePickerNavigationController:
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
self.preserveCurrentEntity = YES;
[self presentViewController:picker animated:NO completion:nil];
UIImagePickerController will break just for picking videos, but work for everything else, this is the code I use:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
switch (buttonIndex) {
case ImagePickerModeCamera:
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
break;
case ImagePickerModeAlbum:
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
break;
default:
break;
}
imagePicker.delegate = self;
NSMutableArray *mediaType = [[NSMutableArray alloc] init];
switch (self.actionSheetType) {
case ActionSheetTypeImage:
[mediaType addObject:(NSString*)kUTTypeImage];
break;
case ActionSheetTypeVideo: {
[mediaType addObject:(NSString*)kUTTypeMovie];
[mediaType addObject:(NSString*)kUTTypeVideo];
imagePicker.allowsEditing =NO;
}
break;
default:
break;
}
imagePicker.mediaTypes = mediaType;
[self presentViewController:imagePicker animated:NO completion:nil];
This is what happens in iOS7 when loading ABPeoplePickerNavigationController:
This is what happens in iOS8 when loading ABPeoplePickerNavigationController:
What is the solution to fix this?
Looks like I found the solution to my problem.
I have a root view controller that has two xibs, one for iPad and one for iPhone. It seems my iPad one was causing the trouble even though they were very similar (just one was larger). I couldn't figure out why.
I just use the iPhone one now and make sure it resizes correctly on iPad and everything is working correctly.
I have the same problem like you, but after wasting some time I got some post, that what may be the reason in your case.
iPhone Library does not work on the iOS Simulator in special case of picking Vedio
Referred Post for my solution. and worked for me.
Update on it, if you still facing problem, I can post my code to help you.
HTH, Enjoy Coding !!

Access to CAMZoomSlider instance to clear it's delegate

I am presently using UIImagePicker and my app crashes on iOS 8 with the following workflow:
Start the camera, zoom it which shows the zoom slider below and then take a picture. Select Use Photo and app crashes.
After looking more into the crash "didHideZoomSlider" message is sent to the deallocated instance of image picker view.
Here is my code:
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeImage, nil];
imagePicker.allowsEditing = YES;
imagePicker.delegate = self;
[myController presentViewController:imagePicker animated:animated completion:nil];
I tried a couple of things. My controller holds a strong reference to the image picker, I tried making it a weak reference and the app still crashes. Also I need a strong reference so I actually cannot make it weak.
Although this looks like an Apple bug and someone has already logged it (http://openradar.appspot.com/18762927) I wanted to try the workaround they are using. However I am not able to get to "CAMZoomSlider" through UIImagePicker's instance.
Does anyone know how to get to CAMZoomSlider?
I was able to clear the CAZoomSlider delegate by doing the following in a subclassed UIImagePickerController class. And sure enough, it seems to have resolved the crash.
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self clearZoomSliderDelegate:self.view.subviews];
}
- (void)clearZoomSliderDelegate:(NSArray*)subviews
{
for (UIView *subview in subviews)
{
if ([subview isKindOfClass:NSClassFromString(#"CAMZoomSlider")])
{
if ([subview respondsToSelector:#selector(setDelegate:)]) {
[subview performSelector:#selector(setDelegate:) withObject:nil];
}
return;
}
else if (subview.subviews != nil) {
[self clearZoomSliderDelegate:subview.subviews];
}
}
}

ios 8 completion block not called

In my app I am using TTOpenInAppActivity to insert "Open in" action inside UIActivityController.
Inside it works like this:
Some view controller presents UIActivityController with TTOpenInActivity already built in.
-(void)openWithAction
{
NSURL *fileURL = SOME_URL;
CGRect rect = SOME_RECT;
TTOpenInAppActivity *openInAppActivity = [[TTOpenInAppActivity alloc] initWithView:self.view andRect:rect];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[fileURL] applicationActivities:#[openInAppActivity]];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
// Store reference to superview (UIActionSheet) to allow dismissal
openInAppActivity.superViewController = activityViewController;
// Show UIActivityViewController
[self presentViewController:activityViewController animated:YES completion:NULL];
} else {
// code for iPad, irrelevant
}
}
When user taps "Open in" button, the following method is triggered:
- (void)performActivity
{
if(!self.superViewController){
[self activityDidFinish:YES];
return;
}
// Dismiss activity view
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
// iPhone dismiss UIActivityViewController
[self.superViewController dismissViewControllerAnimated:YES completion:^(void){
if (self.fileURLs.count > 1) {
[self openSelectFileActionSheet];
}
else {
// Open UIDocumentInteractionController
[self openDocumentInteractionControllerWithFileURL:self.fileURLs.lastObject];
}
}];
} else {
// code for iPad, irrelevant
}
}
}
As the app is for iPhone only, this piece of code should be executed:
[self.superViewController dismissViewControllerAnimated:YES completion:^(void){
if (self.fileURLs.count > 1) {
[self openSelectFileActionSheet];
}
else {
// Open UIDocumentInteractionController
[self openDocumentInteractionControllerWithFileURL:self.fileURLs.lastObject];
}
}];
In iOS7 everything works fine. In iOS8 UIActivityController is dismissed and then nothing happens.
While debugging I did manage to detect that in iOS8 completion handler is never called.
Please, help me find out the reason for this behavior and make it work as it should.
Thank you in advance.
In iOS 8, when you tap on "Open in", UIActivityViewController is dismissed automatically. So, when you call self.superViewController dismissViewControllerAnimated:completion:, viewController was already dismissed and method do nothing (so completion not called).

iOS 7 UIImagePicker preview black screen

When i try to load camera from my code, camera preview is black. If I wait for 10-20 seconds it will show real camera preview. I found several questions and some of them suggest that running some other code in background should be the reason for this. However I don't have any code running in background.
How should I fix this?
This is my code where I run camera
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:photoPicker animated:YES completion:NULL];
About 5 months ago my team discovered a memory leak with UIImageViewController in iOS7. Each instantiation slowed down the app exponentially (i.e. first alloc-init had a 1 second delay, second had a 2 second delay, third had a 5 second delay). Eventually, we were having 30-60 delays (similar to what you're experiencing).
We resolved the issue by subclassing UIImagePickerController and making it a Singleton. That way it was only ever initialized once. Now our delay is minimal and we avoid the leak. If subclassing isn't an option, try a class property in your viewController and just lazy load it like so.
-(UIImagePickerController *)imagePicker{
if(!_imagePicker){
_imagePicker = [[UIImagePickerController alloc]init];
_imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
return _imagePicker;
}
Then you can just call it later like:
[self presentViewController:self.imagePicker animated:YES completion:nil];
Had this myself - it happens if something is running on the main dispatch thread - are you resizing images by any chance?
It puts the preview onto the main thread and if something is using it, you get a black screen. It's a bug and the workaround is to either take over the main thread or to disable the photo picker until the queue is free
This Should work for you:
- (void)cameraViewPickerController:(UIImagePickerController *)picker
{
[self startCameraControllerFromViewController: picker
usingDelegate: self];
}
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
// Displays a control that allows the user to choose movie capture
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, (NSString *) kUTTypeMovie,nil];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
[controller presentViewController:cameraUI animated:YES completion:nil];
return YES;
}

Resources