dealloc UIImagePickerController error - ios

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.

Related

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

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];
}

Custom transition between UIViewControllers does not work

I have object that manage custom transition:
#interface NavigationManager : NSObject <UIViewControllerAnimatedTransitioning>
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;
#property (nonatomic, assign) NSTimeInterval presentationDuration;
#property (nonatomic, assign) NSTimeInterval dismissalDuration;
#property (nonatomic, assign) BOOL isPresenting;
#end
#interface NavigationManager()
#property (nonatomic, strong) id<UIViewControllerContextTransitioning> transitionContext;
#end
#implementation NavigationManager
#synthesize presentationDuration, dismissalDuration, isPresenting;
-(id)init{
self = [super init];
if(self){
self.presentationDuration = 1.0;
self.dismissalDuration = 0.5;
}
return self;
}
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return self.isPresenting ? self.presentationDuration : self.dismissalDuration;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
if(self.isPresenting){
[self executePresentation:transitionContext];
}
else{
[self executeDismiss:transitionContext];
}
}
...
#end
And in class that should process implement transitions:
#interface ViewController : UIViewController <UIViewControllerTransitioningDelegate>
#property (nonatomic, strong) NavigationManager navigationManager;
..
#end
#implementation
...
//Here I`m doing navigation to new UIViewController
- (void)navigateToNewScreen
{
DetailedNewsController *secVC = [[DetailedNewsController alloc] init];
secVC.fullDescription = fullDescription;
secVC.headerImage = a.imageView.image;
self.transitioningDelegate = self;
[self.navigationController pushViewController:secVC animated:YES];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
self.animationController.isPresenting = YES;
return self.animationController;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.animationController.isPresenting = NO;
return self.animationManager;
}
#end
Default animation of transitioning is performed. Also navigation controller bar is not displayed after navigation.
UPDATE:
I thing problem in way how I`m creating UINavigationController in AppDelegate:
firstVC = [[ViewController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:firstVC];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor blackColor];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
I'll make an answer with the new information you have provided. The reason I make it an answer is that I just don't want to give you some copy paste code, but to try to give a brief explanation behind it. If I understand correctly, you now want to present a ViewController with a custom transition.
So you got the custom transition working by changing your code to this:
secVC.transitioningDelegate = self;
secVC.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:secVC animated:YES completion:nil];
Since we got that up and running, what's currently missing is the NavigationBar of the ViewController you want to show. Since you're presenting a ViewController, it won't be contained within the existing NavigationController stack in which the the ViewController you're presenting is within.
Therefore, you need to wrap your VC you want to present within a UINavigationController.
[self presentViewController:[[UINavigationController alloc] initWithRootViewController:secVC] animated:YES completion:nil];

Open Camera in another View in iOS

How can I call this method from my MainController.m class and pass the Image to my MainController
CameraController.m
- (void) openCamera {
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.delegate = self;
picker.sourcetype = UIImagePickerContrllerSourceTypeCamera;
[self presentViewContrller:picker animated:YES completion:nil];
}
I'm still a newbie in iOS development and is it possible to use a delegate?
Edit:CameraController doesn't have a nib.
In CameraController.h add these lines:
#protocol CameraControllerDelegate <NSObject>
- (void)didFinishCapturingImage:(UIImage*)image;
#end
and add a property in CameraController class (in CameraController.h)
#property (nonatomic, strong) id<CameraControllerDelegate> delegate;
In MainController.h, add protocol in interface implementation; like this:
#interface MainController : NSObject <CameraControllerDelegate>
before you present/push CameraController from your MainController.m add this line:
cameraController.delegate = self;
In MainController.m implement didFinishCapturingImage method.
- (void)didFinishCapturingImage:(UIImage*)image {
//your logic
}
in Image Picker Controller Delegate, add this line:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion: Nil];
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
//this will send delegate callback to MainController
[self.delegate didFinishCapturingImage:image];
}
EDIT: Second Solution:
Make a property in CameraController.h to keep instance of MainController object:
#property (nonatomic, strong) MainController *mainController;
Assign self to CameraController's instance's property mainController where you use CameraController:
cameraController.mainController = self;
Edit you openCamera method:
- (void) openCamera {
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.delegate = self.mainController; //important line
picker.sourcetype = UIImagePickerContrllerSourceTypeCamera;
[self.mainController presentViewContrller:picker animated:YES completion:nil];
}
and implement following method in MainController.m
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//your logic
}
Don't forget to include UIImagePickerControllerDelegate in MainController.h.
No need to create protocols and implement protocol methods..

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];
}

Different URI for each instance of UIViewController

I have a UITabController with five tabs. Each tab simply holds an instance of a custom UIViewController, and each instance holds a UIWebView.
I want the UIWebView in each tab to open a different URI, but I don't think it should be necessary to create a new class for each tab.
I can make it work if I do [self.webView loadRequest:] in -(void)viewDidLoad but it seems ridiculous to create five different classes with five different versions of viewDidLoad when all I really want to change is the URI.
Here's what I've tried:
appDelegate.h
#import <UIKit/UIKit.h>
#interface elfAppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UITabBarController *tabBarController;
#end
appDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
customVC *start = [[customVC alloc] init];
customVC *eshop = [[customVC alloc] init];
customVC *table = [[customVC alloc] init];
customVC *video = [[customVC alloc] init];
customVC *other = [[customVC alloc] init];
// Doesn't do anything... I wish it would!
[start.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]]];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[start, eshop, table, video, other];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
customVC.h
#import <UIKit/UIKit.h>
#interface customVC : UIViewController <UIWebViewDelegate> {
UIWebView* mWebView;
}
#property (nonatomic, retain) UIWebView* webView;
- (void)updateAddress:(NSURLRequest*)request;
- (void)loadAddress:(id)sender event:(UIEvent*)event;
#end
customVC.m
#interface elfVC ()
#end
#implementation elfVC
#synthesize webView = mWebView;
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[UIWebView alloc] init];
[self.webView setFrame:CGRectMake(0, 0, 320, 480)];
self.webView.delegate = self;
self.webView.scalesPageToFit = YES;
[self.view addSubview:self.webView];
}
Create a property of type NSURL* in your customVC.
Change your customVC's -(id)init method to -(id)initWithURL:(NSURL*)url as follows:
-(id)initWithURL:(NSURL*)url{
self = [super init];
if(self){
self.<URLPropertyName> = url;
}
return self;
}
Then call
[start.webView loadRequest:[NSURLRequest requestWithURL:self.<URLPropertyName>]];
in viewDidLoad
Then when you initialize your different instances of customVC, just use
customVC *vc = [customVC alloc]initWithURL:[NSURL URLWithString:#"http://..."]];
I suspect you are initialising your webview after calling it's loadRequest: method. To avoid this, it's a better practice to initialise nonatomic properties by overriding their setters:
- (UIWebView*)webview {
if (mWebView == nil) {
// do the initialization here
}
return mWebView;
}
This way your webview will be initialised when you first access it (while calling loadRequest:) and not after it, in your custom view controller's viewDidLoad method.

Resources