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;
}
Related
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];
}
}
}
I need your help/references/hints on how to get a pictures from 1) my Gallery in iPhone and 2)from the iPhone front camera. So that my program copies this picture to its local folder on iPhone (not just referencing to Gallery). Thanks
You might find the info on this appple developer doc useful. You use UIImagePickerController to present a modal view, as shown in the code below, from the doc above.
- (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// Displays saved pictures and movies, if both are available, from the
// Camera Roll album.
mediaUI.mediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeSavedPhotosAlbum];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
mediaUI.allowsEditing = NO;
mediaUI.delegate = delegate;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
I do suggest you read through the doc above, as it is very informative but not easily paraphrasable.
Hope this helps!
I have a UICollectionView and a bar button at top right(CameraViewController1 : UICollectionViewController).The flow is when I take a picture it moves to a new view controller where the image can be cropped.User has two option Use and Cancel after choosing any of this option it gets back the image to the collection view and it gets arranged like cells.I want to take many photos.But I can take up to 3 pictures only where as the app crashes immediately and shows a message "App terminated due to memory pressure".But the worst part is when I tested the same app in iPhone 5 running iOS 7 the crash wasn't happen.When I test the same in iPhone 4 running iOS 7 it gets crashed and produce received memory warning.
Here my code
- (IBAction)TakeaPhoto:(id)sender {
[[UIApplication sharedApplication]setStatusBarHidden:FALSE withAnimation:NO];
gallery=0;
picker1 = [[UIImagePickerController alloc] init];
picker1.delegate = self;
self.resizeableCropArea =YES;
self.cropSize=CGSizeMake(300,350);
//picker1.allowsEditing = YES;
picker1.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:picker1 animated:YES completion:NULL];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissViewControllerAnimated:YES completion:NULL];
UIImage *image = [info objectForKey: UIImagePickerControllerOriginalImage];
image_cap = [self imageTemp:image scaledToSize:CGSizeMake(320, 370)];
dataTemp = UIImageJPEGRepresentation(image,0.0);
CropViewController *cropController = [[CropViewController alloc] init];
cropController.sourceImage = [info objectForKey:UIImagePickerControllerOriginalImage];
Original_img = UIImageJPEGRepresentation(cropController.sourceImage,0.0);
[original_image addObject:[UIImage imageWithData:Original_img]]; //original_image Nsmutablearray
NSLog(#"source image=%#",cropController.sourceImage);
cropController.resizeableCropArea = self.resizeableCropArea;
cropController.cropSize = self.cropSize;
cropController.delegate = self;
Cancel_Image= cropController.sourceImage;
[self.navigationController pushViewController:cropController animated:YES];
}
#Ramanan R R, I m totally agree with the #Rushabh's comment..
You are allocating that UIImagePickerController for many more times, as TakeaPhoto method call you are allocating UIImagePickerConrtoller, it is not necessary to allocate that multiple times. It makes memory spoilage, thats why your app is going to terminate or crash..
Just allocate that one time in viewDidLoad, make sure one more thing that, do
UIImagePickerController as a strong property, because in past it took my whole day to solve issue...
Hope this will work for you and your app will run smoothly...:)
Since the iOS7 upgrade, I have a weird behaviour of the UIImagePickerController. In this application I am using the UIImagePickerController with a cameraOverlayView.
In iOS6 I called the UIImagePickerController using the following code:
_picker = [[UIImagePickerController alloc] init];
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
_picker.sourceType = UIImagePickerControllerSourceTypeCamera;
_picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
_picker.cameraDevice = UIImagePickerControllerCameraDeviceRear;
_picker.showsCameraControls = NO;
_picker.navigationBarHidden = NO;
_picker.toolbarHidden = YES;
_picker.wantsFullScreenLayout = YES;
_overlayViewController = [[OverlayViewController alloc] init];
_overlayViewController.picker = _picker;
_overlayViewController.frameSize = self.frameSize;
_overlayViewController.delegate = self;
_picker.cameraOverlayView = _overlayViewController.view;
}
else {
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
_picker.delegate = self;
Where the OverlayViewController is an UIViewController, with a transparent background which draws some custom controls on screen.
But now in iOS 7 the camera is drawn through the statusbar and a black bar appears beneath the live camera view.
I can solve this by applying a CGAffineTransformMakeTranslation to the cameraViewTransform property of the UIImagePickerController, but why is this like this?
In iOS 7, by default UIViewController views take up the entire screen area including the status bar.
wantsFullScreenLayout
is deprecated and ignored. In some cases, this fix works (in the view controller class):
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
In other cases, it's a bit more complicated. It's late here, so see how you go with it. Helpful things to note - in a UIViewController, the following code will give the correct statusbar height on both iOS 6 and iOS 7, should it come to having to align things using CGRect math:
if (UIDeviceOrientationIsLandscape(self.interfaceOrientation)) {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.width;
} else {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
}
And then don't forget that in Interface Builder, there are the new "iOS 6 delta" adjustments that allow you to design for iOS 7 and then use offsets to correct for iOS 6.
Anyhow, let me know how you go.
My understanding of the issue, based on a few other SO threads and such, is that UIImagePickerController does not do what we'd expect in terms of managing the status bar via [UIViewController -prefersStatusBarHidden].
This means you either have to disable view controller status bar management entirely, via plist, or figure out a way to get UIImagePickerController to do what we want. On the assumption that you're not looking for the former, I can say I've had success in the latter by putting the picker in a wrapper controller that does what I want (but fall back to your previous code if you still need to detect/support iOS6):
#interface PickerContainer : UIViewController
#property ( nonatomic, weak ) UIImagePickerController* picker;
#end
#implementation PickerContainer
- (void) setPicker: (UIImagePickerController*) picker
{
[self addChildViewController: picker];
[picker didMoveToParentViewController: self];
self->_picker = picker;
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.picker.view.frame = self.view.bounds;
[self.view addSubview: self.picker.view];
}
// Will have no effect in ios6 -- see [-init] for that option
- (BOOL) prefersStatusBarHidden { return YES; }
- (id) init
{
if ( ! ( self = [super init] ) ) return nil;
if ( detectThatThisIsIos6() ) self.wantsFullScreenLayout = YES;
return self;
}
#end
This will work for you, scaled camera, you will have a black bar at the bottom but it will get overlayed by tool bar
https://stackoverflow.com/a/15803947
I have a UIViewController with a UITableView as subview. When a certain cell was clicked an UIImagePickerController should be presented. Because of the long initialization time it takes, I perfom this process in the background when the UIViewController did appear.
Now I added ARC to my project and then it didn't still work. The UI was freezed by the initial process.
Here's my code.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self performSelectorInBackground:#selector(initImagePickerControllerInBackground) withObject:nil];
}
...
- (void)initImagePickerController
{
if (imagePickerController != nil)
return;
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.allowsEditing = YES;
imagePickerController.delegate = self;
imagePickerController.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage];
}
- (void)initImagePickerControllerInBackground
{
#autoreleasepool
{
[self initImagePickerController];
}
}
What should I change to get it working for me?
UIKit is not a thread safe class and should not be called from outside the main thread. You should not perform this UIImagePickerController allocation/interaction in the background.