Main app stop responding to events after UIViewController ends - ios

i'm simply trying to show the camera or photo library so the user can select an image and return to the app. I could finally do it, but the problem that i'm facing, is that when the UIViewController ends (why the user selected an image or why the user pressed cancel) the app works, but events stopped working.
my UIViewController is defined like this:
#interface IOSNativeCb : UIViewController
- (void)imagePickerControllerUIImagePickerController *)picker didFinishPickingMediaWithInfoNSDictionary *)info;
#end
#implementation IOSNativeCb
- (void)imagePickerControllerUIImagePickerController *)picker didFinishPickingMediaWithInfoNSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
[picker release];
//log all the dictionary of the selected image
for (id key in info) {
NSLog(#"key: %#, value: %# \n", key, [info objectForKey:key]);
}
}
//if user canceled
- (void)imagePickerControllerDidCancelUIImagePickerController *)picker {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[picker dismissViewControllerAnimated:YES completion:^{[self dismissViewControllerAnimated:YES completion:nil];}];
[self removeFromParentViewController];
[window makeKeyAndVisible];
}
#end
and i'm initializing with this from openfl:
const void initAppGallery(){
UIWindow *window = [UIApplication sharedApplication].keyWindow;
IOSNativeCb *wn = [[IOSNativeCb alloc] init];
[window addSubview: wn.view];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = wn;
[wn presentModalViewController:picker animated:YES];
[picker release];
}
tried several things in how i remove or dismiss the UIViewController to see if maybe the view still was principal and for that reason the events didn't worked anymore, but nothing so far.
any ideas of what i could try? anyone had any problem like this? is my first time coding in objetive-c + haxe, so i'm a bit lost of what functions or things could be the problem. i'm coding blind in a language i barely know.
Regards.

Some things that could help you find the error:
Use window.rootViewController = wn instead of [window addSubview:wn.view]
Don't release the picker after calling [picker dismissModalViewControllerAnimated:YES]. You already released the picker once on the initAppGallery method, so releasing it again could lead to unknown problems (probably crashes)
Calling [window makeKeyAndVisible] should be done at the end of initAppGallery.
Take also a look to this question, it might help you a bit.

the solution was more simple, i just added after [self removeFromParentViewController];:
[self.view removeFromSuperview];
and worked :D

Related

iOS show view controller from NSObject not working

I am trying to show a image picker view controller from a NSObject subclass but when i call presentViewController on the app's root vc the app crashes without a error message.
My code is here:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
UIViewController *root = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController];
[root presentViewController:picker animated:YES completion:nil];
If i run this in a view controller it just works fine.
EDIT:
I can't use a delegate because i am building a plugin for Unity and i can't get the view controller in other ways than this.
I noticed the crash while calling this code in the current view controller from a IBAction:
- (IBAction)showPicker:(id)sender {
PhotoManager *manager = [[PhotoManager alloc] init];
[manager loadPhoto];
}
In answer to the comments here's the class code:
PhotoManager.h:
#interface PhotoManager : NSObject <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
- (void)loadPhoto;
#end
.m:
#implementation PhotoManager {
UIViewController *root;
}
- (void)loadPhoto {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
root = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController];
[root presentViewController:picker animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[root dismissViewControllerAnimated:YES completion:nil];
NSLog(#"%#", info);
}
#end
The proper way would be to create a protocol / delegate and call back to the presenting viewController telling it to present the picker. This allows you to do much more and is a great habit to learn right away IMO.
How do I set up a simple delegate to communicate between two view controllers?

presentViewController-- Attempt to present __ on __ whose view is not in the window hierarchy

I'm attempting to do a presentViewController with an UIImagePickerControl in order to display a standard Camera Roll photo picker. This works end-to-end in most of my app. The place where it does not work is when I want to use the imagePicker inside an already presented viewController; the view to present the album is unable to be presented.
The basic idea is I'm trying to either access the rootViewController on the window object, or the app delegate's persisted tabBarController (which is the rootViewController); both as examples of top level items that are hopefully always present. Just using "self" otherwise ends up as a partial view presenting it.
Is there a reliable way to presentViewController inside an already presentedView?
dispatch_async(dispatch_get_main_queue(), ^ {
// 1. attempt that works well elsewhere in app
[((AppDelegate*)[[UIApplication sharedApplication] delegate]).tabBarController presentViewController:self.imagePickerController animated:YES completion:nil];
// 2. this does nothing, no crash or action (_UIAlertShimPresentingViewController)
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:self.imagePickerController animated:YES completion:nil];
// 3. attempt off related internet suggestion, nothing happens
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
[topController presentViewController:self.imagePickerController animated:YES completion:nil];
});
Because presentViewController is meant as a modal presentation, I don't think it's possible to present a second modal at the same time in the same UIWindow. You could, however, add a new UIWindow and present it there.
originalWindow = [[[UIApplication sharedApplication] keyWindow];
tempWindow = [[UIWindow alloc] init];
UIViewController *controller = [[UIViewController alloc] init];
tempWindow.rootViewController = controller;
[tempWindow makeKeyAndVisible];
[controller presentViewController:self.imagePickerController animated:YES completion:nil];
You'll want to add something like this in your response to the image picker's return:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Process the result and then...
[self cleanupWindow];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self cleanupWindow];
}
- (void)cleanupWindow {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(madeKeyWindow:) name:UIWindowDidBecomeKeyNotification object:nil];
[originalWindow makeKeyAndVisible];
}
- (void)madeKeyWindow:(NSNotification *)notification {
[tempWindow removeFromSuperview];
tempWindow = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIWindowDidBecomeKeyNotification object:nil];
}

Understanding how to dismiss a UIImagePickerController

I'm a bit confused, this isn't a question on how to dismiss a UIImagePickerController, it's more of a "why did that work" type of question. I am working in iOS7.
Looking online at the apple documentation (this link: https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/CameraAndPhotoLib_TopicsForIOS/Articles/TakingPicturesAndMovies.html#//apple_ref/doc/uid/TP40010406-SW6), I came across the following code for dismissing a UIImagePickerController:
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
Edit: I know that that method was deprecated, so instead I tried the following, and that did not work either:
[[picker parentViewController] dismissViewControllerAnimated:YES completion:NULL];
Those didn't work for me. This however did work:
[picker dismissViewControllerAnimated:YES completion:NULL];
Is the apple documentation wrong? or just outdated?
Why does the second bit of code work, because from my understanding, its the parent view controllers job to dismiss something like a popover or in this case a UIImagePickerController
Thank you.
Edit: This is how I am presenting the UIImagePickerController, the UITapGestureRecognizer calls the first method which then calls the second.
- (IBAction)captureMoment:(UITapGestureRecognizer *)sender {
[self startCameraCaptureFromViewController:self usingDelegate:self];
}
- (BOOL)startCameraCaptureFromViewController:(UIViewController *)controller
usingDelegate:(id <UIImagePickerControllerDelegate, UINavigationControllerDelegate>)delegate {
if (delegate == nil || controller == nil || [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) {
return NO;
}
UIImagePickerController *camera = [[UIImagePickerController alloc] init];
camera.sourceType = UIImagePickerControllerSourceTypeCamera;
camera.allowsEditing = NO;
camera.delegate = delegate;
[controller presentViewController:camera animated:YES completion:NULL];
return YES;
}
There are 2 methods that worked for me
Use picker.presentingViewController instead of picker.parentViewController, answer by rmaddy
Use the following code in the imagePickerControllerDidCancel:, [picker dismissViewControllerAnimated:YES completion:NULL];
Here is the code in its entirety, this is placed in the UIViewController that presents the UIImagePickerController:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
}
The method dismissModalViewControllerAnimated has been deprecated since iOS6. The new method you are using is the correct one.

Xcode5 error : Warning attempt to present <View> on <OtherView> while presentation is in progress

I am still a noob when it comes to making applications for iOS and I don't understand why I am getting a certain error. For my current project I am trying to switch views but I cannot get it to work and I do not really understand why. I followed this tutorial for the button(http://www.youtube.com/watch?v=ph3XhJD8QAI) and although the tutorial is older, it still works. I had to edit some of the code to make sure that it worked for Xcode 5 though. Every time I press the button to switch the views I get an error that reads "Warning: Attempt to present < SecondView: 0xc918d50 > on < SeriouslyFunnyView: 0xc91a130 > while a presentation is in progress!" and the screen in the iPhone Simulator just goes black. I am also using Storyboard, i'm not sure if that is relevant to the situation or not. Can anyone possibly tell me what I am doing wrong ? Let me know if I need to add more code for clarification ! Thanks in advance for the help
Here is my code for the button that switches views
-(IBAction)SwitchView:(id)sender {
SecondView *second = [[SecondView alloc] initWithNibName:nil bundle:nil];
[self presentViewController:second animated:YES completion:NULL];
}
You must dismiss completely a view before present another. Try with:
[self dismissViewControllerAnimated:YES completion: ^{
SecondView *second =
[[SecondView alloc] initWithStyle:UITableViewStylePlain];
controller.modalTransitionStyle = UITableViewStylePlain;
[self presentViewController:second animated:YES completion:nil];
}];
comment the body of switchview, and check whether any controller is presented on click of switchview.. that looks silly but may be it'd b helpful to find out which controller is in progress... i'm also not used to storyboards ,, so .. hope that helps
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// TODO: make this all threaded?
// crop the image to the bounds provided
img = [info objectForKey:UIImagePickerControllerOriginalImage];
NSLog(#"orig image size: %#", [[NSValue valueWithCGSize:img.size] description]);
// save the image, only if it's a newly taken image:
if ([picker sourceType] == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
}
// self.image_View.image = img;
// self.image_View.contentMode = UIViewContentModeScaleAspectFit;
NSLog(#"Picker has returned");
[self dismissViewControllerAnimated:YES
completion:^{
ModalViewController *sampleView = [[ModalViewController alloc] init];
[self presentModalViewController:sampleView animated:YES];
}];
}

Variables not kept when changed in a callback

I am making a game made in C++ which at some point wants to open make use of the camera.
To do this it interfaces with an Objective C class which presents the modal view controller:
UIImagePickerController* cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects:(NSString*)kUTTypeImage, nil];
cameraUI.allowsEditing = YES;
cameraUI.delegate = self;
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentModalViewController:cameraUI animated:YES];
This class exposes a State variable to allow the game to watch the progress of the modal view controller.
It is initalized:
State = CAMERA_ACTIVITY_WORKING;
And updated by the UIImageControllerDelegate functions:
- (void)imagePickerControllerDidCancel: (UIImagePickerController*) picker
{
State = CAMERA_ACTIVITY_CANCELED;
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}
- (void)imagePickerController: (UIImagePickerController*) picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
State = CAMERA_ACTIVITY_IMAGECAPTURED;
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}
The modal view controller opens and closes as it should and the delegates definately get called. However, when the game polls the State variable it appears to have not been updated returning CAMERA_ACTIVITY_WORKING.
I have tried making the variable volatile but this had no effect.
Can anybody help?
Edit: Full Class Source Code
.h
#interface Camera : UIViewController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
volatile State State;
UIImage* CapturedImage;
}
- (void)imagePickerControllerDidCancel: (UIImagePickerController*) picker;
- (void)imagePickerController: (UIImagePickerController*) picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
- (bool) IsAvailable;
- (bool) Show;
- (State) GetState;
#end
.m
#implementation Camera
- (id)init
{
self = [super init];
if(!self) return self;
State = CAMERA_ACTIVITY_WORKING;
CapturedImage = NULL;
return self;
}
- (void)imagePickerControllerDidCancel: (UIImagePickerController*) picker
{
DEBUG_LOG("imagePickerControllerDidCancel");
State = Poppet::ICameraActivity::CAMERA_ACTIVITY_CANCELED;
DEBUG_LOG("State: " + STRING_CAST(State));
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}
- (void)imagePickerController: (UIImagePickerController*) picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
State = CAMERA_ACTIVITY_IMAGECAPTURED;
[[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}
- (bool) IsAvailable
{
return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == YES;
}
- (bool) Show
{
if(![self IsAvailable]) return false;
State = CAMERA_ACTIVITY_WORKING;
UIImagePickerController* cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera; //Get Image From Camera
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects:(NSString*)kUTTypeImage, nil];
cameraUI.allowsEditing = YES;
cameraUI.delegate = self;
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentModalViewController:cameraUI animated:YES];
return true;
}
- (State) GetState
{ return State; }
#end
It looks like your not using your custom Camera class.
You create a class
UIImagePickerController* cameraUI = [[UIImagePickerController alloc] init];
set the delegate and some other items and display it to the user. But this is not an instance of a Camera class, it's an instance of UIImagePickerController. I believe you want to do
Camera* cameraUI = [[Camera alloc] init];
which will give you the implementation of your custom UIViewController however there is a another problem. Your Camera class is not a sub-class of UIImagePickerController, it is a sub-class of UIViewController so it will not be a UIImagePickerController. I think you intended it to be
#interface Camera : UIImagePickerController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
On a side note, naming convention says only Class names should start with capital letters. Method names and variables should start with lower case letters.
Edit from comment:
Your Show method doesn't appeared to be called from anywhere, so I'm not sure how it would be used. More than that, looking at the method, I'm not sure how it would be used. The - at the beginning means it's an instance method which can only be called on an instance of Camera, but it is used to create and show an instance of Camera so the method requires and instance of an object to create and display a newly created instance of the object. Probably not what is intended. You could use a + to make it a class method and call it with [Camera Show], but you wouldn't be able to access instance variables because they would not exist.
Currently, I don't see anywhere where a Camera is created (outside Show) and could become the active view controller so it looks like you are just displaying a generic UIImagePickerController and not your custom class.

Resources