UIImagePickerController crashed with "[UIViewController _setCameraOverlayView:]: unrecognized selector" on iOS 11 - ios

I'm trying to create a customized UIImagePickerController with the following code.
ECPhotoPickerController.h
#interface ECPhotoPickerController : UIImagePickerController
#property (strong, nonatomic) void(^didFinishSavingPhoto)(NSURL* url, UIImage* image);
#property (strong, nonatomic) void(^didDismissed)(void);
#end
ECPhotoPickerController.m
...
- (void)viewDidLoad {
[super viewDidLoad];
self.sourceType = UIImagePickerControllerSourceTypeCamera;
self.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
self.showsCameraControls = false;
[self setCameraOverlayView:self.overlayView];
self.delegate = self;
}
...
The customized image picker controller will be presented after I tapped a button, which would invoke the following method.
- (void)showImagePicker {
ECPhotoPickerController* vc = [[ECPhotoPickerController alloc] init];
vc.didFinishSavingPhoto = ^(NSURL *url, UIImage *image) {
self.selectedImage = image;
};
vc.didDismissed = ^{
// dismissed
};
[self presentViewController:vc animated:true completion:nil];
}
But the app will only crash on iOS 11 with the log
[UIViewController _setCameraOverlayView:]: unrecognized selector sent to instance 0x108403dd0
and there is anther weird log before the crash.
[] <<<< AVOutputDeviceDiscoverySession (FigRouteDiscoverer) >>>> -[AVFigRouteDiscovererOutputDeviceDiscoverySessionImpl outputDeviceDiscoverySessionDidChangeDiscoveryMode:]: Setting device discovery mode to DiscoveryMode_None (client: ECalligraphy)
The customized image picker class obviously inherit from UIImagePickerController.
And when I initialized it with [[ECPhotoPickerController alloc] init], it should invoke the super class's initialization since I didn't implement the initialization of ECPhotoPickerController.
I'm really confused about this crash.
Any advice will be appreciated.

I final found the reason!
The sourceType should be specified before the view controller start to be
load on iOS 11.
That means, you should set the value of sourceType during the initialization of your customized view controller or do it for the instance before load.
- (instancetype)init { // `initFromNibName` etc. depends on the way you initialize it.
if (self = [super init]) {
self.sourceType = UIImagePickerControllerSourceTypeCamera;
self.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
self.showsCameraControls = false;
self.delegate = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
Or
- (void)showImagePicker {
ECPhotoPickerController* vc = [[ECPhotoPickerController alloc] init];
vc.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:vc animated:true completion:nil];
}

Related

dealloc UIImagePickerController error

I have a view which contains a button image picker. When I close the view I am also deallocating the UIImagePickerController.
#interface XXPictureCell()<UIImagePickerControllerDelegate>
#property (nonatomic, strong) UIImagePickerController *imagePickerController;
#end
#implementation XXPictureCell
- (void)dealloc
{
self.imagePickerController.delegate = nil;
}
//...
- (UIImagePickerController *)imagePickerController
{
if (!_imagePickerController)
{
_imagePickerController = [[UIImagePickerController alloc] init];
_imagePickerController.delegate = self;
_imagePickerController.allowsEditing = YES;
_imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
_imagePickerController.cameraDevice = UIImagePickerControllerCameraDeviceFront;
}
return _imagePickerController;
}
#end
The error I keep receiving is
Cannot form weak reference to instance (0x7fa9e18dc600) of class XXPictureCell. It is possible that this object was over-released, or is in the process of deallocation.

how to fix over released objects

NSZombie detected that one of the objected is over released in my app and that is causing the app to crash every time when a button is pressed. However, after inspecting the source code of where the over release happens, I couldn't see any obvious code that that may have caused the release. Can xcode release objects automatically without any actual code?
Below are the places reported by the Instrument that has a release event:
-(void) takePicture:(CDVInvokedUrlCommand *)command {
CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
self.pickerController = cameraPicker;
CameraOverlayViewController* overlay = [[CameraOverlayViewController alloc] initWithNibName:#"CameraOverlayViewController" bundle:nil];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.cameraOverlayView = overlay.view;
[self.viewController presentViewController:cameraPicker animated:YES completion:nil];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
Any ideas on how to fix the problem? Thanks in advance!
I think CameraOverlayViewController is released.
Try the below code
CameraOverlayViewController* overlay;
-(void) takePicture:(CDVInvokedUrlCommand *)command {
CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
self.pickerController = cameraPicker;
overlay = [[CameraOverlayViewController alloc] initWithNibName:#"CameraOverlayViewController" bundle:nil];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.cameraOverlayView = overlay.view;
[self.viewController presentViewController:cameraPicker animated:YES completion:nil];
}
You're creating a CameraOverlayViewController and keeping a reference to it's view, but the CameraOverlayViewController itself is going out of scope when the takePicture: method ends. A view doesn't retain it's view controller. You need to either keep a reference to the CameraOverlayViewController, or if you're only interested in the view object itself, just create a view from the xib file and set the cameraPicker.cameraOverlayView to that view.
EDIT:
For example, in your header file you could make a property:
#property (strong) CameraOverlayViewController *overlay;
and in your method:
-(void) takePicture:(CDVInvokedUrlCommand *)command {
CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
self.pickerController = cameraPicker;
self.overlay = [[CameraOverlayViewController alloc] initWithNibName:#"CameraOverlayViewController" bundle:nil];
cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraPicker.cameraOverlayView = self.overlay.view;
[self.viewController presentViewController:cameraPicker animated:YES completion:nil];
}
Once you're done with the camera, you'll want to let go of the reference. So for example:
-(void) cameraPickerFinished {
self.overlay = nil;
}

iOS how to start the image picker

I have a UIButton and when the user clicks it, I want to start the image picker controller
I already configure what I think it is enough but I couldn't know what is the message that I have to pass to that image picker to start working
This is my code
#import "ImagePickerViewController.h"
#interface ImagePickerViewController ()
#property (weak, nonatomic) IBOutlet UIImageView *image;
#end
#implementation ImagePickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)SelectImage:(id)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
#end
I have already set the correct protocols:
#interface ImagePickerViewController : UIViewController < UINavigationControllerDelegate,UIImagePickerControllerDelegate>
#end
You need to present the UIImagePicker
- (IBAction)SelectImage:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:NO completion:nil];
}
You can show the picker with:
[self presentViewController:imagePicker animated:YES completion:NULL];
And then in your delegate callback imagePickerController:didFinishPickingMediaWithInfo you get the image and dismiss the picker again:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerEditedImage];
[picker dismissViewControllerAnimated:YES completion:NULL];
}
You have to tell your view controller class to show the UIImagePickerController.
Simply use
[self presentViewController:imagePicker animated:YES completion:nil];
This will present it modally. If you are running on an iPad, you instead have to present it in a popover controller, as follows:
Declare a new property in the #interface:
#property (nonatomic, strong) UIPopoverController* imagePickerPopover;
Present the popover controller e.g:
UIButton* button = sender;
self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:self.imagePicker];
[self.imagePickerPopover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];

iOS: Screen no longer receives Touches after calling dismissModalViewController

I have two views. Very simple set up just to play around with the camera roll.
One view will bring up the camera roll using:
[self presentViewController:self.imagePicker animated:NO completion:nil];
which is triggered by a UIButton. It brings up the camera, everything's fine.
After taking a picture, I am calling the following to dismiss the controller:
[self dismissViewControllerAnimated:NO completion:nil];
Again, everything is working.
But the view that brings up the imagePicker Controller no longer receives touch (the UIButton will no longer brings up the camera again) after the Modal View is dismissed.
It will only start to receive touches again when I switch to another view and come back.
I have been searching for a solution to this problem but have not been successful in finding anything. Thanks in advance.
EDIT (Adding code):
In CameraController.m
This is where brings up the Camera Roll
(Subclass of UIViewController conforming to
<UIImagePickerControllerDelegate, UINavigationControllerDelegate>)
//UIButton that brings up the imagePicker
- (IBAction)useCamera
{
[self prepareImagePicker];
[self presentViewController:self.imagePicker animated:NO completion:nil];
}
//Initializing ImagePicker
- (void)prepareImagePicker
{
if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera])
{
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
self.imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
self.imagePicker.delegate = self;
OverlayCameraView *cameraOverlay = [[OverlayCameraView alloc] initWithFrame:(CGRect){{0, 0}, 320, 480} andTheCameraController:self];
self.imagePicker.cameraOverlayView = cameraOverlay;
}
}
//Delegate Method when a picture is taken
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.imagePicker.delegate = nil;
[picker dismissViewControllerAnimated:NO completion:nil];
self.imagePicker = nil;
self.imageView.image = [info objectForKey:UIImagePickerControllerOriginalImage];
}
In OverlayCameraView.m
//Camera Overlay Class (Subclass of UIView)
- (id)initWithFrame:(CGRect)frame andTheCameraController:(CameraController*)cameraController
{
if ((self = [super initWithFrame:frame]))
{
self.camera = cameraController;
//.…2 UIButtons set up
}
return self;
}
//Overlay Cancel Button
- (void) cancel
{
[self.camera dismissViewControllerAnimated:NO completion:nil];
}
//Overlay Take Picture Button
- (void) takeAPicture
{
[self.camera.imagePicker takePicture];
}
You should be calling dismissViewControllerAnimated on the picker not self via the UIImagePickerControllerDelegate methods.
[picker dismissViewControllerAnimated:NO completion:nil];
or if you are keeping a reference to it:
[self.imagePicker dismissViewControllerAnimated:NO completion:nil];
EDIT:
Based on the revised code, I believe
self.imagePicker.cameraOverlayView = cameraOverlay;
should be:
self.imagePicker.cameraOverlayView = cameraOverlay.view;
Also this will cause a +2 reference count and will leak if you are not using ARC:
self.imagePicker = [[UIImagePickerController alloc] init];
It should be for proper reference counting:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
self.imagePicker = picker;
[picker release];

Make a UIView display the camera view using UIImagePickerController

I'm trying to display the image a the camera sees into my own custom view. I DO NOT want to use Apple's own overlay property for UIImagePickerController: cameraOverlayView.
I don't want an overlay, but for it to just display in my particular view. The only way I've been able to do it was creating a subview in my UIView, but doing this doesn't allow me to use any of my own custom buttons I've made over my UIView . My code so far is:
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
[imagePickerController setSourceType:UIImagePickerControllerSourceTypeCamera];
[imagePickerController setShowsCameraControls:NO];
[imagePickerController setEditing:NO];
[imagePickerController setNavigationBarHidden:YES];
[self.videoPreviewView addSubview:[imagePickerController view]];
[imagePickerController viewWillAppear:YES];
where videoPreviewView is the outlet for my UIView!
Any suggestions? Thanks!
I have not tried it your way myself, but I also wanted to create a custom camera view. This might not be what you are looking for, but it is an alternative. I created a custom UIView together with .xib file.
In the .m file you just call the appropriate delegate methods to the ViewController where you instantiated the imagePicker. In this ViewController you then call appropriate methods like takePicture.
This way you can make the overlay look any way you like with the xib file. You can instantiate the image picker
FALKCameraView.h :
#protocol CameraViewDelegate <NSObject>
- (void)cameraPressed;
- (void)buttonPressed;
//etc
#end
#interface FALKCameraView : UIView
#property (nonatomic, assign) NSObject<CameraViewDelegate> *delegate;
//Camera Button pressed- notifies CameraViewDelegate
- (IBAction)cameraPressed:(id)sender;
//Button pressed - notifies CameraViewDelegate
-(IBAction)buttonPressed:(id)sender;
#end
FALKCameraView.m:
#implementation FALKCameraView
#synthesize delegate;
- (IBAction)cameraPressed:(id)sender{
[delegate cameraPressed];
}
-(IBAction)buttonnPressed:(id)sender{
[delegate buttonPressed];
}
#end
FALKCameraViewController.h:
#interface FALKCameraViewController : UIViewController <UIImagePickerControllerDelegate, CameraViewDelegate>
- (void)cameraPressed;
- (void)buttonPressed;
#end
FALKCameraViewController.m:
#interface FALKCameraViewController
#property (strong,nonatomic) UIImagePickerController *imagePicker;
#end
#implementation FALKCameraViewController
#synthesise imagePicker;
-(void)setUpCamera{
if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera]){
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType =
UIImagePickerControllerSourceTypeCamera;
imagePicker.showsCameraControls = NO;
imagePicker.allowsEditing = NO;
imagePicker.mediaTypes = #[(NSString *) kUTTypeImage];
NSString *nibName = #"FALKCameraView";
NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
options:nil];
if([nibs count]){
id nib = [nibs objectAtIndex:0];
if([nib isKindOfClass:[FALKCameraView class]]){
FALKCameraView *view = (FALKCameraView*)nib;
view.delegate = self;
imagePicker.cameraOverlayView = view;
}
}
[self presentViewController:imagePicker
animated:NO completion:nil];
}
}
-(void)cameraPressed:(id)sender{
[imagePicker takePicture];
}
#end
Hope it will work and i just added a single view you can add any custom object to overlayview of the picker
if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera]){
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType =
UIImagePickerControllerSourceTypeCamera;
imagePicker.showsCameraControls = NO;
imagePicker.allowsEditing = NO;
NSString *nibName = #"CameraView";
NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
options:nil];
if([nibs count]){
id nib = [nibs objectAtIndex:0];
if([nib isKindOfClass:[CameraView class]]){
CameraView *view = (CameraView*)nib;
view.delegate = self;
imagePicker.cameraOverlayView = view;
}
}
[self presentViewController:imagePicker
animated:NO completion:nil];
}

Resources