Simultaneously dismissing a view controller and then presenting one - ios

So I have a VC that i call on when a button is clicked (It's a MFMailComposeViewController) and when the message is sent, It dismisses the ViewController and i want it to present a different one once it's done sending. But instead of doing this it crashes after sending the email every time. i know I'm doing something wrong but i'm not sure what.
Here's my code that dismisses and presents the new one.
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:true completion:nil];
[self presentViewController:_emailConfirmationPage animated:YES completion:nil];}
I was thinking that the problem was that I used self but I'm not sure what I use in place of that.

It is crashing because you are asking for both dismiss and present animations to begin simultaneously. So you can fix this in 2 ways:
Wait for the first animation to complete before starting the next one. This will animate the dismissal of the current VC and animate the presentation of the new one. Of course the user would have to wait for both animations to complete before they can continue interacting with the app. To do this, present _emailConfirmationPage in the completion block of dismissing the current VC like this:
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:_emailConfirmationPage animated:YES completion:nil];
}];
Animate either dismiss OR present, but not both. This might be better because the user would have to wait only for 1 animation and that 1 animation will most probably be sufficient to ensure a fluid user experience.
[self dismissViewControllerAnimated:NO completion:nil];
[self presentViewController:_emailConfirmationPage animated:YES completion:nil];

Try put your [self presentViewController:_emailConfirmationPage animated:YES completion:nil];} into completion: block in the [self dismissViewControllerAnimated:true completion:nil]; , it will execute present vc after it has complete dismiss the other vc
Like this:
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:_emailConfirmationPage animated:YES completion:nil];
}];
Your code did not work because its still animating dismissViewController and there can't be 2 animation at the same time

Related

Attempt to dismiss from view controller (UIModalViewController) while a presentation or dismiss is in progress

I have just started working on ios.
I created a Modalviewcontroller (VC1) and presented another modalViewcontroller (VC2).
There is a button (dismiss) on VC2 which will have to dismiss both viewcontrollers.
The way i know is call :-
[self dismissViewControllerAnimated:YES completion:nil];
in VC2
then call the same in VC1
So i created a delegate which tells me if dismiss is clicked in VC2.
so when dismiss is clicked:-
i call
[self dismissViewControllerAnimated:YES completion:nil];
in VC2
then that delegate method takes me to VC1
where I again call
[self dismissViewControllerAnimated:YES completion:nil];
This method was perfectly working till i was using the app in ios9
when i shifted to ios7 i started getting the warning and VC1 was not getting dismissed.
Please let me know why is this happening.
So the part which works for me as told in comments.
[self.presentedViewController dismissViewControllerAnimated:YES completion:^{
[self dismissViewControllerAnimated:YES completion:nil];
}];
So, error tells you exactly what happened. You trying to dismiss VC1, while your VC2 dismissing. By putting dismissViewControllerAnimated into delegate method does not guarantee that VC1 will be dismissed before, instead of that you should call your [self dismissViewControllerAnimated:YES completion:nil]; in completion block after first dismiss, so your code will look like that:
[self dismissViewControllerAnimated:YES
completion:^{
[self dismissViewControllerAnimated:YES completion:nil];
}];

Switch views quickly in iOS

I have a view A, a view B and a view C. The idea is : I'm presenting view B on view A, view B has a delegate in view A that performs a segue : view C.
My problem is I have the message "Attempt to present view B on view A while a presentation is in progress!".
I can make it work adding a delay in the method of view A that performs the segue, but isn't there a better way to make it work ?
In view A, the delegate method :
- (void)addItemViewController:(NSString *)string text:(NSString *)textfield{
[self barcodeData:string type:1 :^(BOOL finished) {
if(finished){
[self performSegueWithIdentifier:#"viewC" sender:self];
}
}];
}
In view B
[self.delegate addItemViewController:saisieManuelleTextView.text text:nil];
[self dismissViewControllerAnimated:NO completion:nil];
Try invoking the delegate in the animation completion handler (some overlap in postings as redent84 also suggested this):
[self dismissViewControllerAnimated:YES completion:^{
[self.delegate addItemViewController:saisieManuelleTextView.text text:nil];
}];
That way you're still getting the benefits of the delegate and avoid the possibility of simultaneous view controller animations.
Better yet, if view A presents view B, then make viewA responsible for dismissing viewB as well, instead of having viewB dismiss itself. That way viewB doesn't have to know how it was presented in the first place:
- (void)addItemViewController:(NSString *)string text:(NSString *)textfield{
[viewB dismissViewControllerAnimated:YES completion:^{
[self barcodeData:string type:1 :^(BOOL finished) {
if(finished){
[self performSegueWithIdentifier:#"viewC" sender:self];
}
}];
}];
}
The problem that you are seeing is related to the animation of the transitions. You are trying to animate the transition from view A to view C while there's already a transition active from view B back to view A.
Try using the completion block of the dismissViewControllerAnimated method:
[self dismissViewControllerAnimated:YES completion:^{
[self performSegueWithIdentifier:#"MySegue" sender:self];
}];
Or try disabling the animation of the transition from the view B to view A so it doesn't affect at all:
// For navigation controllers
[self.navigationController popViewControllerAnimated:NO];
// For modal controllers
[self dismissViewControllerAnimated:NO completion:nil];
EDIT:
You are presenting the new controller before dismissing the previous one, change the following lines:
[self.delegate addItemViewController:saisieManuelleTextView.text text:nil];
[self dismissViewControllerAnimated:NO completion:nil];
to this:
[self dismissViewControllerAnimated:NO completion:nil];
[self.delegate addItemViewController:saisieManuelleTextView.text text:nil];
Alternatively, you can maintain the animation using the completion block as described above:
[self dismissViewControllerAnimated:YES completion:^{
[self.delegate addItemViewController:saisieManuelleTextView.text text:nil];
}];

dismissViewControllerAnimated results in empty screen

I present modal view which is a navigation controller:
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:photoEditVC];
[self presentViewController:nvc animated:YES completion:NULL];
Once I'm done with the modal view, inside nvc's visible controller:
[self.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
Result
Any ideas why this could happen?
UPDATE:
I realized this only happens when before dismissing the view, I update a value in a shared singleton class, I use to keep track of events.
[[SAStatus current] setValue:#(ua_photoSubmitted) forKeyPath:#"actions.user"];
[self dismissViewControllerAnimated:YES completion:NULL];
But it works fine if I do this:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[[SAStatus current] setValue:#(ua_photoSubmitted) forKeyPath:#"actions.user"];
}];
or I can do this and it also works fine:
[self dismissViewControllerAnimated:YES completion:^{
[[SAStatus current] setValue:#(ua_photoSubmitted) forKeyPath:#"actions.user"];
}];
At the time, no other classes observer that variable so I do not understand why it would affect the modal view.
Not sure that this is causing the black screen, but the presented view controller should call dismissViewController on itself, not on the presenting view controller.
[self dismissViewControllerAnimated:YES completion:nil];
I saw this issue with iOS 8 GM. Dismissing with animated set to NO did the trick.

Can't dismiss FBfriendPickerViewController from delegate method

I am using the facebook FBFriendPickerViewController and want the user to only be able to select one friend and then have it dismiss the view controller. In the FBFriendPickerDelegate, under the selectionDidChange method I am trying to capture what friend they selected and then dismiss the view controller. I can't get it to dismiss, I feel like I have done this type of thing many times before so I feel kind of dumb asking this, but I feel like I have exhausted every variation of this and nothing works.
-(void)friendPickerViewControllerSelectionDidChange:(FBFriendPickerViewController *)friendPicker{
self.selectedFriends = friendPicker.selection;
NSLog(#"%#", self.selectedFriends);
[friendPicker dismissViewControllerAnimated:YES completion:nil];
}
I have also tried
[[friendPicker parentViewController] dismissViewControllerAnimated:YES completion:nil];
[self.friendPickerController dismissViewControllerAnimated:YES completion:nil];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[[friendPicker navigationController] dismissViewControllerAnimated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
all to no avail.
Since it's a navigation Viewcontroller that you likely pushed, you would want to pop it:
[self.navigationController popViewControllerAnimated:YES];
If you present the friendpicker controller modally you can dismiss it by using the facebookViewControllerCancelWasPressed and the facebookViewControllerDoneWasPressed methods of the FBViewControllerDelegate protocol. If you conform to FBFriendPickerDelegate you automatically conform to the first one.

Can't call the back button on a UITabBarController

I have a tab bar controller with a view inside a navigation controller. One of the buttons on this pops up a modal view. I set my starting view as the delegate for the modal, and call the following:
- (void)dischargeSaveComplete:(dischargeView *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
It correctly dismisses the modal view, but it doesn't call the back button. Do I need to do something else since it's inside a tab bar controller?
I tried set both to animation no as seen below, and it doesn't work either.
- (void)dischargeSaveComplete:(ehrxEncounterDischargeView *)controller
{
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController popViewControllerAnimated:NO];
}
Found the solution based on one of the answers, because I was in a tab bar controller, I had to call the popviewcontroller from the first view as seen below:
- (void)dischargeSaveComplete:(ehrxEncounterDischargeView *)controller
{
[self dismissViewControllerAnimated:YES completion:^(void)
{
demoView *e = [self.parentViewController.tabBarController.viewControllers objectAtIndex:0];
[e.navigationController popViewControllerAnimated:YES];
}];
}
You want 2 animations to follow one another, which is not allowed as you did it. You either have to cancel one of the animation or place popViewController inside the completion block for your first animation.
[self dismissViewControllerAnimated:YES completion:^(void) {
[self.navigationController popViewControllerAnimated:YES];
}
];
u can try delay in performing second action
[self.navigationController performSelector:#selector(popViewControllerAnimated:) withObject:#"YES" afterDelay:1];
hope it works.. happy coding :)

Resources