performSegueWithIdentifier not working - objective-c

I have this code that loads a new UIView (from storyboard) when a button is pressed. goPressed function is fired on button pressed and it calls selectImage function. selectImage opens a UIImagePickerController and lets user select a photo. After user has selected the photo, didFinishPickingMediaWithInfo delegate adds the selected image to a UIImageView.
In 'goPressed', after selectImage is performed, it should be performing a Segue at like commented as //1. But nothing happens. performSegueWithIdentifier doesn't seem to be working. And if I don't call [self selectImage] before calling performSegueWithIdentifier, it works. Here is the code:
- (IBAction)goPressed:(id)sender {
[self selectImage];
[self performSegueWithIdentifier:#"lastView" sender:currentSender]; //1
}
-(void)selectImage
{
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Delegate is self
imagePicker.delegate = (id)self;
// Allow editing of image ?
imagePicker.allowsEditing=NO;
// Show image picker
[self presentModalViewController:imagePicker animated:YES];
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[[picker presentingViewController] dismissModalViewControllerAnimated:YES];
lePreview.image= image;
}
Please help, why performSegueWithIdentifier isn't working? I hope I am not missing any information you need.

I'm assuming that the view you are trying to segue to is using the picture you get just before you do your segue? If they cancel from the image picker do you still want to segue?
If it needs the picture, then maybe you should call your segue after the delegate call "did finish picking".
The issue with the segue not firing may be due to the animation still occurring from here:
[[picker presentingViewController] dismissModalViewControllerAnimated:YES];
You can try:
[[picker presentingViewController] dismissModalViewControllerAnimated:NO];
or if you want to maintain the animation, move the segue to the "picker did finish" method and do it this way:
[self dismissModalViewControllerAnimated:YES completion:^() {
[self performSegueWithIdentifier:#"lastView" sender:self];
}];
or if that does not work try this approach in the pickerdidfinish method (note - this should be implemented as a delegate in the controller that calls the modal view, not the modal view itself:
//maintain the animation
[self dismissModalViewControllerAnimated:YES];
//slight pause to let the modal page dismiss and then start the segue
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//code to be executed on the main queue after delay
[self performSegueWithIdentifier:#"lastView" sender:self];
});
I use this transition frequently and it makes a nice drop away with the modal view then slides in the segue view and the pause allows the transition to seem natural.

Related

Attempt to present modal VC on VC whose view is not in the window hierarchy

I have a storyboard that looks like this:
This is how it works: the InitialSlidingViewController instantiates the Navigation VC as the topViewController as follows in its .m file:
-(void)viewDidLoad {
[super viewDidLoad];
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Navigation"];
}
After the Navigation VC gets instantiated, it creates the underlying Menu and sets that as the underLeftVC. This is using ECSlidingViewController. This creates a sliding menu that uses a pan gesture, similar to Facebook.
The rootVC for the NavigationVC is my ItemsCDTVC. When I click the + button, it pops up an action sheet that allows me to take a photo from the camera or choose from the photo library. However, I then want it to modally segue to the ManageItemVC and set the picture I just chose/took to its UIImageView. When I try to present, it throws the following error:
Warning: Attempt to present <ManageItemViewController: 0x81d52a0> on <InitialSlidingViewController: 0x8122ce0> whose view is not in the window hierarchy!
Which is true, because InitialSlidingVC is not on screen, ItemCDTVC is, but how do I fix this?
I have set the modal type segue in my Storyboard with an identifier from the flexible space at the bottom (when tapped, it doesn't do anything, so I chose that to create a visual segue). This is my segue code in ItemCDTVC:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// let's get the edited image
UIImage *image = info[UIImagePickerControllerEditedImage];
// but if for some reason we disable editing in the future, this is our safeguard
if(!image) image = info[UIImagePickerControllerOriginalImage];
if(image) {
self.pictureImageView.image = image;
[self performSegueWithIdentifier:#"addItemSegue" sender:self];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"addItemSegue"]){
ManageItemViewController *manageItemVC = (ManageItemViewController *)[segue destinationViewController];
manageItemVC.pictureImageView = self.pictureImageView;
}
}
It fails when trying to present the modal VC.
Fixed, the only thing I had to do is dismiss the imagePickerController before trying to perform the segue, as so:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// let's get the edited image
UIImage *image = info[UIImagePickerControllerEditedImage];
// but if for some reason we disable editing in the future, this is our safeguard
if(!image) image = info[UIImagePickerControllerOriginalImage];
if(image) {
self.pictureImage = image;
[self dismissViewControllerAnimated:NO completion:^{
[self performSegueWithIdentifier:#"addItemSegue" sender:self];
}];
}
}

iOS:View controller crashes when trying to use camera in an application.

I have a button where when the user presses it, he is navigated to camera to take a pic.
When he takes the pic, he presses done and gets back to the controller. But when that happens the navigation bar gets up in the screen, gets below the battery/signal bar that the telephone has. The weird thing is that this happens on 4/4s but not on 3gs
It is rather tough to answer the question without knowing a bit more details, but here's some code I use to bring up the camera, take the picture, then close the camera successfully. The method can be called by using one line of code: [self takePhoto];
- (void) takePhoto {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
//Clear out the UI first
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
//picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; -> use this if you want them to select from the library
[self presentViewController:picker animated:YES completion:nil];
} else {
//Device does not support a camera, show a message if desired
}
}
Then you need a delegate for it all so the program knows what to do when an image is taken or selected and how to close, that's what this code is:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
self.workingImage = nil;
//I grab the image and store globally, but first I manually scale and rotate it if necessary
self.workingImage = [self scaleAndRotateImage:[info objectForKey:UIImagePickerControllerOriginalImage]];
//I display the image in my UI view, so this chunk of code will size it properly
CGRect bound;
bound.origin = CGPointZero;
bound.size = img.size;
imageView.bounds = bound;
//Set the UI image view and dismiss the controller
[imageView setImage:self.workingImage];
[picker dismissModalViewControllerAnimated:YES];
}
Obviously, make sure your controller .h implements the delegate properly like so:
#interface ViewController : UIViewController<UIImagePickerControllerDelegate> { ... }
Hope this helps?

iOS - increase partial curl tap area to dismiss modal

Is there a way to do this? Like tapping on any part of the screen dismisses the partial modal curl.
I thought about an invisible button, but that still doesn't cover the whole curl area.
Add gesture recognizers to your main view in viewDidLoad
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(getDismissed)];
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(getDismissed)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
tapRecognizer.delegate = self;
[self.view addGestureRecognizer:tapRecognizer];
[self.view addGestureRecognizer:swipeRecognizer];
-(void)getDismissed
{
// call dismissViewControllerAnimated:completion: by the presenting view controller
// you can use delegation or direct call using presentingViewController property
}
Then exclude in view that you don't want to trigger the dismissal
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// touching objects of type UIControl will not dismiss the view controller
return ![touch.view isKindOfClass:[UIControl class]];
}

Making a UIViewController a UIImagePicker when tapped

I have an app that uses the UITabBarController and one of the tabs is supposed to be a full on camera view (similar to Instagram). When I launch the app and go to that view, most of the screen is blank and no image library picker/camera view loads. Any help would be greatly appreciated.
Here is my viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
imagePicker = [[UIImagePickerController alloc] init];
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}
[imagePicker setDelegate:self];
[imagePicker setEditing:NO];
// Place image picker (camera viewing angle on the screen)
[self presentViewController:imagePicker animated:YES completion:nil];
}
Try putting that code in viewDidAppear instead -- that worked for me. Better yet, would be to put all but the last line in viewDidLoad, so it's only called once, and just put the last line in the viewDidAppear method. When you cancel the image picker (the only thing I tested), it will just reappear, since viewDidAppear will be called again, so you need to implement imagePickerControllerDidCancel: like this to keep that from happening:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissViewControllerAnimated:YES completion:nil];
self.imagePicker = nil;
}
And, in your viewDidAppear, put in an if statement to see if the picker exists before trying to present it:
if (self.imagePicker) {
[self presentViewController:self.imagePicker animated:YES completion:nil];
}

How show activity-indicator when press button for upload next view or webview?

when i click on button which title is click here to enlarge then i want show activity indicator on the first view and remove when load this view.
but i go back then it show activity indicator which is shown in this view.
in first vie .m file i have use this code for action.
-(IBAction)btnSelected:(id)sender{
UIButton *button = (UIButton *)sender;
int whichButton = button.tag;
NSLog(#"Current TAG: %i", whichButton);
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[spinner setCenter:CGPointMake(160,124)];
[self.view addSubview:spinner];
[spinner startAnimating];
if(whichButton==1)
{
[spinner stopAnimating];
first=[[FirstImage alloc]init];
[self.navigationController pushViewController:first animated:YES];
[spinner hidesWhenStopped ];
}}
in above code i have button action in which i call next view. Now i want show/display activity indicator when view upload. In next view i have a image view in which a image i upload i have declare an activity indicator which also not working. How do that?
Toro's suggestion offers a great explanation and solution, but I just wanted to offer up another way of achieving this, as this is how I do it.
As Toro said,
- (void) someFunction
{
[activityIndicator startAnimation];
// do computations ....
[activityIndicator stopAnimation];
}
The above code will not work because you do not give the UI time to update when you include the activityIndicator in your currently running function. So what I and many others do is break it up into a separate thread like so:
- (void) yourMainFunction {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[NSThread detachNewThreadSelector:#selector(threadStartAnimating) toTarget:self withObject:nil];
//Your computations
[activityIndicator stopAnimating];
}
- (void) threadStartAnimating {
[activityIndicator startAnimating];
}
Good luck!
-Karoly
[self.navigationController pushViewController:first animated:YES];
Generally, when you push a view controller into navigation controller, it will invoke the -(void)viewWillAppear: and -(void)viewDidAppear: methods. You can add activity indicator view inside the viewWillAppear: and call startAnimation of indicator view. You CANNOT invoke startAnimation and stopAnimation at the same time. For example,
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings ....
[aIndicatorView stopAnimation];
}
Because the startAnimation and stopAnimation are under the same time, then no animation will show.
But if you invoke startAnimation in -(void)viewWillAppear: and invoke stopAnimation in another message, like followings.
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings...
}
- (void)viewDidAppear:(BOOL)animated
{
[aIndicatorView stopAnimation];
}
Because viewWillAppear: and viewDidAppear: are invoked with different event time, the activity indicator view will work well.
Or, you can do something like followings:
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// Let run loop has chances to animations, others events in run loop queue, and ... etc.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];
// do somethings ....
[aIndicatorView stopAnimation];
}
The above example is a bad example, because it invokes two or more animations in the -runUntilDate:. But it will let the activity indicator view work.
Create a webview. Add a activity indicator to the webview. If you are loading a image via url into the webview then implement the webview delegate methods. Once the url is loaded then stopanimating the activity indicator.
Let me know which step you are not able to implement.