I'm having a problem getting my modal view controller to properly display and then dismiss. Basically I have a modally displayed login window and I want to dismiss it after all the data that I want to display is loaded from the database. if I call
[self dismissModalViewControllerAnimated:YES] from within the LoginViewController class it works perfectly fine but if I call
[[mainController modalViewController] dismissModalViewControllerAnimated:YES] from within my datamanager class after I have successfully imported the data nothing happens. Which is extremely confusing because [mainController modalViewController] points to the locationManager class.
Does anybody have any ideas as to why this isn't working? I'm programming for iOS 4 if that matters.
Thanks!
OK So I figured this out. Basically what was happening was that the [self dismissModalViewController] call was happening on another thread which for whatever reason means that the object did not properly process the dismiss message. I ended up using a notification and then called dismissModalView controller like so:
- (void)dismissSelf
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)receiveDismissNotification:(NSNotification *) note
{
[self performSelectorOnMainThread:#selector(dismissSelf) withObject:nil waitUntilDone:NO];
}
which works
The proper way to dismiss a modal view controller is to call -dismissModalViewControllerAnimated: on the view controller that presented it. Thus it should be [_splitViewController dismissModalViewControllerAnimated:YES];.
From your comment, you need to call -dismissModalViewControllerAnimated: on the main thread, you can do this like so:
dispatch_async(dispatch_get_main_queue(), ^{
[_splitViewController dismissModalViewControllerAnimated:YES];
});
To close the Model View Controller use following code
[self dismissModalViewControllerAnimated:YES];
This code works with ios 5 also.
For presenting the model view controller
if (self.viewController!=nil)
{
//sanity check for view controller
[self.viewController SOMEVIEW animated:YES];
}
Related
I am an iOS rookie. I have a Table View embedded in a Navigation Controller. Another Table View is also embedded in a Navigation Controller. The first Table View, ChecklistsView, presents the second Table View, ItemDetailView. The ChecklistView's Navigation Controller '+' button opens the ItemDetailView scene. Tapping on the Cancel button of the ItemDetailView closes the ItemDetailView, but gives the message noted above. Here is the code for the Cancel method:
- (IBAction)cancel
{
[self.delegate itemDetailViewControllerDidCancel:self];
}
And here is the delegate method used in the cancel method:
- (void)itemDetailViewControllerDidCancel:(ItemDetailViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Any suggestions would be appreciated. I have reviewed other posts about this warning, but they are above my level of expertise.
You shouldn't have the delegate dismiss the viewController.
Rather you should dismiss it by using the .presentingViewController property on the presentedViewController.
Like so:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
I disagree with AdamG. What you're doing is correct; Apple also uses this design, where the delegate dismisses the controller (check out MFMessageComposeViewController).
Back to the question, if I understand you correctly, and that you have the following structure (pardon the terms, but you'll get the gist):
A UINavigationController at the top
ChecklistsViewController is the navigation controller's root view controller
ItemDetailViewController as a modal view controller
ChecklistsViewController is the delegate for ItemDetailViewController
It's just the implementation details in your case.
- (void) itemDetailViewControllerDidCancel: (ItemDetailViewController*) controller
{
[controller dismissViewControllerAnimated: YES
completion: nil];
}
I have TWO UIViewController classes, where in FirstClass i have an UIButton for Login, when user taps on button, i will display SecondClass... For that i have done,
SecondClass *index = [[SecondClass alloc] init];
[self presentModalViewController:index animated:YES];
In SecondClass i have a logout button, which will redirect to FirstClass, for that i have done,
[self dismissModalViewControllerAnimated:YES];
When i press Logout button in SecondClass, i get the warning msg
**Attempt to dismiss from view controller <FirstClass: 0e39w88e160> while a presentation or dismiss is in progress!**
What is the problem here..
Added both iOS 6 and pre-iOS 6 answers:
iOS 5.0 and later
When you logout, add this check before dismissing:
if (![self.presentedViewController isBeingDismissed])
{
[self dismissModalViewControllerAnimated:YES completion:nil];
}
iOS 4.X and less
Add this check before dismissing:
if (![[self modalViewController] isBeingDismissed])
{
[self dismissModalViewControllerAnimated:YES];
}
Call these lines where you logout & then check:
if (![[self modalViewController] isBeingDismissed])
{
[self dismissModalViewControllerAnimated:YES];
}
There are many things that may cause this, here are some options:
You forgot to call super on one of the ViewController methods such as viewWillAppear, viewWillAppear etc. Consult the UIViewController documentation to see when you have to call super.
The dismissModalViewControllerAnimated: method is being called more than once, this can happen if you added a target to the UIButton more than once.
To get better understanding of the problem please paste the code of both view controllers in its entirety.
I know there's like 3-5 similar questions here, but non of the answers solves my problem.
I have a ViewController that opens a modal (table)view controller, which opens another one. Both modal view controllers are in fact table view controllers. I'm trying to dismiss both of them from the second one. I tried every accepted answer on similar question, none of them worked for me.
I tried
[self dismissModalViewControllerAnimated:true]
[self.parentViewController dismissModalViewControllerAnimated:true]
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:true]
[self.presentingViewController dismissModalViewControllerAnimated:true]
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:true]
When I try options 2, 3 and 5, nothing happens at all. When I use options 1, and 4, I see dismiss modal view animation and the underlying view itself for a moment, and then everything goes back to the second modal view (this time without animation).
I'm starting to think that this have something with the fact that I use tableViewControllers for modal views.
Btw, I'm dismissing modal views in didSelectRowAtIndexPath.
Try this:-
When you dismiss your SecondView set a BOOL flag variable in app delegate file and check that variable in your FirstView's viewWillAppear method whether SecondView was open and close or not. If so, then [self dismissModalViewControllerAnimated:true]
typical model view controller behavior would suggest that you dismiss the modal view controller from the calling view controller rather than from self. not a hard and fast rule, but good practice.
to accomplish this, create a protocol:
#protocol MyModalViewControllerDelegate
- (void)modalViewControllerDidFinish;
#end
and make both the parentViewController and FirstModalViewController be implemntors of this protocol.
#interface FirstModalViewController <MyModalViewControllerDelegate>
then in both FirstModalViewController.h and SecondModalViewController.h, add:
#property id<MyModalViewControllerDelegate> modalViewControllerDelegate
in both parentViewController and FirstModalViewController, right before calling presentModalViewController:... , set the following:
modalViewControllerAboutToAppear.modalViewControllerDelegate = self;
[self presentModalViewController:modalViewControllerAboutToAppear animated:YES];
next, in the SecondModalViewController, in the code where you determine that the item needs to be dismissed, call
[self.modalViewControllerDelegate modalViewControllerDidFinish];
now, in FirstModalViewController, implement the following:
- (void)modalViewControllerDidFinish:(MyModalViewController*)controller {
[self dismissModalViewControllerAnimated:YES]
[self.modalViewControllerDelegate modalViewControllerDidFinish];
}
and finally, in the parent view controller, you should be able to perform:
- (void)modalViewControllerDidFinish:(MyModalViewController*)controller {
[self dismissModalViewControllerAnimated:YES]
}
Since I don't use delegate files, I did the following:
To FirstView add field
BOOL mClose;
To FirstView add method
- (void)close
{
mClose = YES;
}
To FirstView method viewDidAppear add
if (mClose)
{
[self dismissModalViewControllerAnimated:YES];
}
To FirstView method which opens SecondView add
[secondView closeWhenDone:self];
To SecondView add field
FirstView *mParent;
To SecondView add method
- (void)closeWhenDone:(FirstView*)parent
{
mParent = parent;
}
To SecondView method which closes it add
[mParent close];
I am having a problems with the dismissViewControllerAnimated method not closing down the view.
What is happening in the app here is:
Cell in ItemViewController is selected.
View is pushed to ItemDetailViewControllerand details are sent through a delegate
User selects 'done' and the event is sent via a delegate to be closed in ItemViewController
All of this works except for the View is not dismissed, there are no errors. Can anyone see what is wrong?
- (void)itemDetailViewControllerDidFinish:(ItemDetailViewController *)controller
{
NSLog(#"Controller: %#", controller);
// Returns - Controller: <ItemDetailViewController: 0x6b68b60>
[self dismissViewControllerAnimated:YES completion:nil];
}
What if you call [controller.navigationController popViewControllerAnimated:YES] instead?
For that matter, what if you call [controller dismissViewControllerAnimated:YES completion:nil] instead of calling it on self?
The answer is in this page:
dismissviewcontrolleranimated-vs-popviewcontrolleranimated
dismissViewController is used when you do not have a navigationcontroller.
Most probably you are using a navigation controller, then use
self.navigationController popViewController instead.
Also take note of lemax his remark: use NULL, not nill for the completionhandler
I had a problem in iOS5 where the standard completion callback was not allowing the view to completely dismiss (only the current pushed view of that modal)
[controller dismissViewControllerAnimated:YES completion:^ {
//
}];
Solution for iOS5 is to not have a callback:
[controller dismissViewControllerAnimated:YES completion:nil];
Had a problem where calling dismissViewControllerAnimated dismissed the keyboard in a UIViewController, but not the view itself.
Solved it by using two calls:
[self dismissViewControllerAnimated:NO completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
an instant one for the keyboard, then an animated one for the controller
Your Situation is -
ItemViewController -> ItemDetailViewController
(pushed on navigationController)
Self.dismissViewController(..) dismiss a view controller that is presented over self(in ur case it is ItemViewController). Here, u did not presented any VC over self, instead u pushed a new VC over navigation stack. So, Correct way to dismiss ItemDetailViewController would be
self.navigationController.popViewController(true). please read the description of dismissViewController(....) to get more clarity.
to show a modal uiview out of my mainView I use:
[self presentModalViewController:myController animated:YES];
and in MyController I close that view with:
[self dismissModalViewControllerAnimated:YES];
But how can I know in the mainView that the modal was finished (to redraw my table)?
Currently I set a local variable to YES in my mainView after starting the modal view an react on viewWillAppear:
[self presentModalViewController:myController animated:YES];
_reloadTableData = YES;
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_reloadTableData) {
_reloadTableData = NO;
[_tableView reloadData];
}
}
Is there a better way to do so ?
Generally speaking, it's not appropriate to dismiss the modal view by the modal view itself.
Instead, you should set your main view as the delegate of the modal view. When you modal view finishes its task, it can let its delegate know and let its delegate dismiss it. This is the very common so-called delegate design pattern in Objective-C.
btw, you may want to consult with some code samples to gain a better understanding of this delegate pattern. I suggest you take a look at one of Xcode's default templates - the Utility Application template. It has a very succinct and simple and straightforward delegate structure built inside.