I am in Xcode 4.5, with an iOS6 target.
Preamble: I have a libraryView (presenting view controller), with a popover containing a search. After the presentation of the search results, tapping a row dismisses the library and segues to entryView. That all works just fine.
My issue: upon closing entryView and returning to the libraryView, the search popover is still visible.
I have tried a number of different methods to remedy this:
I have added a Notification observer in the segue to the search popover, posted a Notification from the search controller, posted from the entryView to the following method located in the libraryView. And, yes, libraryView does have addObserver for this method:
- (void)searchComplete:(NSNotification *)notification
{
NSLog(#"SearchPopover dismiss notification?");
[_searchPopover dismissPopoverAnimated:YES];
}
I have added in testing...
if (_searchPopover.popoverVisible)
{
[_searchPopover dismissPopoverAnimated:YES];
}
To viewDidLoad, viewWillAppear, viewWillDisappear, awakeFromNib... all in the library. I have the searchPopover as a property and have tried it as an ivar.
Nothing I've tried dismisses the popover before the segue or after the return.
Anyone have any ideas? Help would be much appreciated!!!
I have found a solution to this issue... found it at this answer: iOS Dismissing a popover that is in a UINavigationController
But, there was a small additional step to make... correct a typo in the answer and change the "dismissPopover" method into an NSNotification Method. I added a segue for the popover, which normally isn't necessary. The key though, is the setting of the parent's definition of the popover to the UIStoryboardPopoverSegue.
Then, use notification to let the parent know it should dismiss.
From the parent view:
- (void)viewDidLoad
{
... other loading code...
[NSNotificationCenter.defaultCenter addObserver:self selector:#selector(dismissSearch:) name:#"dismissSearch" object:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"SearchSegue"])
{
[segue.destinationViewController setDelegate:self];
_searchPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
}
- (void)dismissSearch:(NSNotification *)notification
{
NSLog(#"SearchPopover dismiss notification?");
[_searchPopover dismissPopoverAnimated:YES];
}
In my child view (SearchView). Ideally, it would be in the didSelectRowAtIndexPath. I found it also worked in the segue to the view where it will display the searched item, which is where I would normally place an addObserver. In this case, it is a postNotification...
[NSNotificationCenter.defaultCenter postNotificationName:#"dismissSearch" object:nil];
One last note: I was using an IBAction that checked for popover visibility when tapping the button... display or dismiss. Found that having this as well as the other method was causing the popover to dismiss immediately upon tapping the button! Commenting out the if/else check for visibility solved that!
Thanks for rdelmar for leading me on this path!
Related
I need a good explanation how can I handle the UINavigationControllers and the UITabBarControllers on iOS6.1 with StoryBoards.
When I load my app (1st ViewController) I need if (FB login = success) it jumps with segues to the 2nd ViewController automatically. Here I think I can't use a UINavigationController like root, apple's HIG don't like it.
I need a UITabBarController that connects to 3 UICollectionViewControllers (one tab for each one). I have to put the UITabBarController like root? If yes, how can I handle the others Viewontrollers between them? Like this:
I need a custom BarButtonItem (like the "Delete All" that you can see on the image 2) on each CollectionViewController, I need to use a UINavigationController for each one?
Let's assume you are happy to use unwind segues (if not there are many ways to do without).
1 When I load my app (1st ViewController) I need if (FB login = success) it jumps with segues to the 2nd ViewController automatically. Here I think I can't use a UINavigationController like root, apple's HIG don't like it.
You 1st VC (lets call it the loginVC)..
- should NOT be contained in the Navigation Controller.
- should be set as the application's initialViewController
Your 2nd VC (lets call it your startVC)
- SHOULD be contained in the Navigation Controller
- in that Navigation Controller's Identity Inspector, assign a storyboardID: #"InitialNavController"
In your App Delegate, let's have a loggedIn BOOL property:
#property (nonatomic, assign) BOOL loggedIn;
Now, in your LogInViewController...
In viewDidAppear check to see if we are already logged in, if so, navigate immediately to your startVC:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([(AppDelegate*)[[UIApplication sharedApplication] delegate] loggedIn]) {
UINavigationController* navController =
[[self storyboard] instantiateViewControllerWithIdentifier:#"InitialNavController"];
[self presentViewController:navController
animated:NO
completion:nil];
}
}
It's important that this is placed in viewDidAppear, not (for example) in viewDidLoad - the segue won't work unless the initial view is properly initialised and onscreen.
Make an unwind Segue (and declare it in loginVC's #interface) … loginVC will be the destination VC if users log out.
- (IBAction)unwindOnLogout:(UIStoryboardSegue *)segue
{
[(AppDelegate*)[[UIApplication sharedApplication] delegate] setLoggedIn:NO];
}
(corrected - removed this line:
[[self presentedViewController] dismissViewControllerAnimated:YES
completion:nil];
we don't need to dismiss as the segue has already done that behind the scenes. This is redundant and logs an error message)
In other viewControllers, whereever appropriate you can make a 'logout' button. CTRL-drag from that button to the 'exit' symbol at the bottom of the ViewController in the storyboard, and you will be able to select this segue as the unwind segue.
2 I need a UITabBarController that connects to 3 UICollectionViewControllers (one tab for each one). I have to put the UITabBarController like root? If yes, how can I handle the others Viewontrollers between them? Like this:
I think you are trying to work out how the tabBarController relates to the NavigationController in the previous viewController (startVC). The answer is, it shouldn't - you really don't want to embed the Tab Bar VC in the previous Nav Controller as it will create weird situations for the Tab Bar's child viewControllers.
The navigation from startVC to the tabBarVC should be via a modal segue, NOT a push segue.
You can make another unwind Segue in startVC to facilitate return from your tabBarController's viewControllers:
- (IBAction)unwindToInitialNavFromModal:(UIStoryboardSegue *)segue {
}
(corrected - removed this line:
[[self presentedViewController] dismissViewControllerAnimated:YES completion:nil];
this method doesn't need any content to perform the dismissing)
3 I need a custom BarButtonItem (like the "Delete All" that you can see on the image 2) on each CollectionViewController, I need to use a UINavigationController for each one?
You won't get a Navigation bar in your tabBarVC by default.
You can provide one in two ways
- embed each child viewController in it's own Navigation Controller;
- manually drag a navigation bar to EACH child viewController's scene.
Either is fine, it really just depends whether you will want navigation to other ViewControllers.
You can then add a barButtonItem on the left or right to connect up to the initialVC's unwind segue (CTRL-drag to the 'exit' symbol).
I have a text field that is apparently successfully calling delegate methods as the following method fires when I tap on the test field, but no keyboard shows.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
NSLog(#"should begin editing");
return YES;
}
Any ideas as to why?
A couple of details: This text field happens to be in a view controller in a storyboard. The first time I segue to this view the text field works fine. The subsequent times I segue to this view it does not work. I imagine this is a big clue to why I am getting the described behavior, but I have not been able to figure it out yet.
I fixed the issue by adding the code below to the prepareForSegue: method. Seems to work.
if (_textField.isFirstResponder) {
[_textTextField resignFirstResponder];
}
I'm having troubles using the storyboard.
I properly connected a button (inside a custom uiviewcell) to a scene (ProfileVC) through push segue (whose identifier is pic2profile).
Besides in the table view controller (HomeVC) that manages the cells I implemented the method prepareForSegue:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"pic2profile"]){
ProfileVC *profile = (ProfileVC *)segue.destinationViewController;
NSLog(#"%#", [segue identifier]);
Tweet *tweet = [tweets objectAtIndex:0];
profile.user = tweet.user;
}
}
As explained in the documentation, once called segue.destinationViewController at the end of prepareForSegue should be displayed the view controller at the end of the segue (ProfileVC in this case).
What happen is that I get (no errors!) a black screen and the method viewDidLoad in ProfileVC is not called though the object "profile" is not null.
Inside the storyboard the ProfileVC scene is linked to its view controller (ProfileVC) and is also set up a Storyboard ID.
I already tried this but it didn't work.
Are you performing a segue to a view controller using the code you have, but have a navigation controller in between? If so you have to use a different way, specifying the navigation controller in between.
If you don't need the navigation controller you can delete it and connect the cell to the view controller and keep the code you have. Otherwise you have to change it.
I'm using storyboarding and have a UITableView containing events, which when clicked load another view with more details. I also have an 'add' button on that list which goes to the same page but doesn't prepopulate the information and changes the banner button.
I do it by setting the detail item with the following method, and then in the configureView method I just check if the detail item exists.
- (void)setDetailItem:(id)newDetailItem {
if (self.detailItem != newDetailItem) {
_detailItem = newDetailItem;
[self configureView];
} }
This works ok, but I thought there might be a better way to distinguish between methods, eg by getting the segue identifier in this new view controller and using that. Is there an easy way to do this or do I need to pass this information through as part of the prepareForSegue method?
Using prepareForSegue: seems right. In general, it's a bad idea for methods to care about the conditions under which they're being called if it's not explicit in their parameters.
i came across of an issue with dismissmodalview. it is apparently depreciated in ios 6. can anyone suggest a fix. i tried this code but still brings up the warning.
if ([[self parentViewController] respondsToSelector:#selector(dismissModalViewControllerAnimated:)]){
[[self parentViewController] dismissModalViewControllerAnimated:YES];
} else {
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}
can anyone suggest anything. basically i am trying to dismiss the modal view which i am using in my view controller.
adrian
Have you tried? I'm using this in one of my projects with success.
[self dismissViewControllerAnimated:YES completion:nil];
You receive a warning because the selector is deprecated in iOS 6 and you use it. If you are targeting iOS 5 and above, you should not be using dismissModalViewControllerAnimated:.
If you really need to use it, you can call performSelector: like so:
if ([[self parentViewController] respondsToSelector:#selector(dismissModalViewControllerAnimated:)]){
[[self parentViewController] performSelector:#selector(dismissModalViewControllerAnimated:) withObject:#YES];
}
A word of advice: it is not considered good practice for a view to close itself. You should create a delegate protocol for your modal view controller, and have the presenting view controller by the modal's delegate.