Presenting a navigation controller on a View Controller from storyboard - xcode

In my app i have a storyboard which has initial view controller as X and then i have a navigation controller which has couple of view controllers attached with it through segue but there is no connection between ViewController x and this navigation controller.
Now based on a button tap in View controller x i want to present this navigation controller.
I am doing this :
func showDashBoard()
{
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let next = storyBoard.instantiateViewControllerWithIdentifier("navigation") as! EBNavigationController
self.presentViewController(next, animated: true, completion: nil)
}
So the navigation view is getting presented with the root view controller but its not showing me animation and also i am getting a warning "Attempt to present on whose view is not in the window hierarchy!
"
Can some one please help me in figuring out what is the best way to do this.
Thanks,

The animation problem can be fixed using next.modalPresentationStyle and next.modalTransitionStyle. Lookup the enums for the possible values and give it the one you want.
You usually get the "Attempt to present on whose view is not in the window hierarchy!" errors when you are calling this function before the view is fully loaded. For instance if you call it in the viewDidLoad method. You should call it only after viewDidAppear is called.

Related

Why in ElCapitan GM and Xcode 7 GM the popover appears outside of the view?

Does someone knows why in ElCapitan GM and Xcode 7 GM the popover appears outside of the view?
The popover is triggered by the "Button".
The picture below is a new project with no code written by me, jut a button.
Is it a bug or a new "feature"?
I just tried it, and it seems that you can't set the popover anchor in the Storyboard. Perhaps this is indeed a bug in the new release.
To display the popover programmatically, set the StoryboardID of your popover view controller, for example: "PopoverViewController". Below, it's implemented in the main view controller as a lazy var, so it's instantiated just once, the first time it's referenced.
Connect an IBAction from your button to the main view controller — here, a function called "displayPopover". The "guard let" statement makes sure the sender can be cast as an NSButton.
Then, just call:
presentViewController:asPopover...
lazy var popoverViewController: NSViewController = {
return self.storyboard!.instantiateControllerWithIdentifier("PopoverViewController")
as! NSViewController
}()
#IBAction func displayPopover(sender: AnyObject) {
guard let button = sender as? NSButton else {return}
self.presentViewController(popoverViewController, asPopoverRelativeToRect: button.frame, ofView: button, preferredEdge: NSRectEdge.MaxY, behavior: NSPopoverBehavior.Transient)
}

Xcode storyboard compilation issue for version 6.3

I am working on a simple table with custom cell in a View controller (iPad App). I have created a separate popover view controller to add new record to the table (data entry only) and I am trying to use same view controller to edit the row also (the selected row in the table view). The popover view works well for creating the new record.
But when I created a connection from the table view cell to the same view controller, the compilation fails with following message:
Interface Builder Storyboard Compilation Error : Couldn't compile
connection: IBCocoaTouchOutletConnection: => anchorView =>
IBUITableViewCell: 0x7fad4ca76d70
If I make the connection as PUSH or MODAL, the compilation goes through and I can execute the app.
I wanted to have the Add/Edit record view as a popover as this has only 4 fields. Now it works only if it is push mode. Can you please help me in solving this issue?
I was able to get this resolved using the custom segue from the cell to the view controller (popover mode). Following are the steps:
Created the custom segue in Storyboard from custom cell to target view controller.
Created a new class file subclass of UIStoryboardSegue and linked this to the custom segue in storyboard.
Used the segue id in prepareForSegue (as usual).
Below is the code I used in the custom segue class:
class myCellSegue: UIStoryboardSegue {
override func perform() {
var sourceVC: UIViewController = self.sourceViewController as! UIViewController
var destVC: UIViewController = self.destinationViewController as! UIViewController
destVC.modalPresentationStyle = .Popover
destVC.preferredContentSize = CGSizeMake(600, 500)
let popoverPresentationVC = destVC.popoverPresentationController
popoverPresentationVC?.sourceView = destVC.view
popoverPresentationVC?.permittedArrowDirections = .Down
// ==== View parameters ========
destVC.view.backgroundColor = UIColor.purpleColor()
sourceVC.view.addSubview(destVC.view)
sourceVC.presentViewController(destVC, animated: false, completion: nil)
}
}
BTW - we can use one custom segue for multiple segue connections.

Split View Controller: How to connect Master View Controller to Detail View Controller?

(Xcode6-beta3, Swift, iOS8, iPad)
In an iPad split-view controller, how do I link the Master View Controller to the Detail View Controller?
In other words, when the user taps on an item on the left, how do I change the view on the right?
I know that in didSelectRowAtIndexPath, I need to call a method... but how do I call a method in the Detail View Controller from the Master View Controller?
Example
Imagine an app to display information on different types of cheeses. We begin by dragging a split-view controller onto the storyboard. A table of items in the master view on the left is set up to read as follows.
Swiss
Cheddar
Brie
On the right, there is simply a Web View inside of the detail view controller, named cheeseViewController. Therein, HTML documents about the selected cheese will be displayed.
An IBOutlet is wired from the web view into cheeseViewController, and a method named 'changeCheese' is set up in the Detail View Controller delegate to swap out the document.
How can I make a tap on "Cheddar" change the information in the detail view?
EDIT: Do I have to modify my AppDelegate.swift file? Using a Master-Detail template, I tried the following, with no luck:
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
// Override point for customization after application launch.
let splitViewController = self.window!.rootViewController as UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as UINavigationController
splitViewController.delegate = navigationController.topViewController as Paragraph
return true
}
I hope I understood your problem correctly: You would like to show the detail information of a selected cheese in your Detailview.
When you create a new Master-Detail-View application in XCode 6 Beta 3, there will be a variable called "detailItem" in your DetailViewController.Swift file:
var detailItem: AnyObject? {
didSet{
self.configureView()
}
You set this detailItem in your MasterViewController.Swift file in the following function:
override func prepareForSegue(segue: UIStoryBoardSegue, sender: AnyObject?){
if segue.identifier == "yourSegueIdentifier" {
let indexPath = self.tableView.indexPathForSelectedRow()
let cheeese = yourCheeseArrayWithDetailInformation[indexPath.row]
(segue.destinationViewController as DetailViewController).detailItem = cheeese
}
}
(Assuming, that you have linked the views with a segue with the identifier: "yourSegueIdentifier" and an array of detailinfo called "yourCheeseArrayWithDetailInformation")
The above mentioned function "configureView" in the DetailView can now access your detailItem, which contains the contents of "cheeese"
I hope this helps you.
Why don't you just post a Notification from didSelectRowAtIndexPath in your Master and add an observer in your Detail View most likely inside your viewDidLoad. You also can handle the selector within the observer method with closure.
If you didn't create a master-detail app (so you have no detailItem), you might use this:
if let
mySplitViewController = splitViewController,
detailView = mySplitViewController.childViewControllers.last as? DetailViewController {
// do something with it
}

I want to go to a specific tab in a UITabBarController from a view controller

First of all, let me say I'm an absolute beginner, so please forgive me if this is a stupid questions to be asking. And let me just add that I've spent hours/days trying to figure out how to solve this problem - including extensive searches on stackoverflow (maybe the answer is somewhere and I just don't now exactly what to search for :)...
But, let's continue: I have a small (?) problem with an Xcode storyboard project. Basically my project looks like this:
Navigation Controller -> View Controller 0 -> Tab Bar Controller -< View Controller 1, View Controller 2, View Controller 3.
When the user pushes 'button #2' in the View Controller 0, I'd like him/her to jump directly to 'View Controller 2'.
Would that be possible at all, and if so what code should use and excatly where should I put it.
Hope someone out there will help a newbie out :)
Regards,
Ulrik
Yes it is possible. You may show any view controller from any other.
You should simply add a segue from button #2 to View Controller 2. (I assume you have all your controllers in single storyboard)
Update: the above solution will show you View Controller 2 itself without tab bar controller.
Hard to tell in details without seeing the actual code. For more details you may refer to these documents:
View Controller Basics (especially part "Storyboards Help You Design Your User Interface")
Presenting View Controllers from Other View Controllers
Using View Controllers in Your App
Probably you'll come up with more concrete question.
Update
If you want to preselect desired view controller inside tabbar controller you may use the following code sketch. Here you can programmatically initiate a segue and do the desired pre-initialization inside prepareForSegue:sender: method.
static NSString * const kShowTabSegueID = #"ShowTab";
#interface ViewController ()
- (IBAction)buttonOnePressed;
- (IBAction)buttonTwoPressed;
- (IBAction)buttonThreePressed;
#end
#implementation ViewController
- (IBAction)buttonOnePressed
{
[self performSegueWithIdentifier:kShowTabSegueID
sender:#0];
}
- (IBAction)buttonTwoPressed
{
[self performSegueWithIdentifier:kShowTabSegueID
sender:#1];
}
- (IBAction)buttonThreePressed
{
[self performSegueWithIdentifier:kShowTabSegueID
sender:#2];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender
{
if ([segue.identifier isEqual:kShowTabSegueID]) {
NSNumber *indexToShow = sender;
UITabBarController *tabBar = segue.destinationViewController;
[tabBar setSelectedIndex:indexToShow.unsignedIntegerValue];
}
}
#end
If you are simply trying to programatically switch tabs, its as simple as:
[self.tabBarController setSelectedIndex:1];
If I am understanding your flow correctly, from ViewController0 you would present ViewController1(that has a UITabBarController). In the viewWillAppear: set the selectedIndex for the tab controller (code above) to index 1, which would be ViewController2.
EDIT
After looking at your project, add this code to your BrainBreaksViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[self.tabBarController setSelectedIndex:1];
}
I added this, and it switches to the 2nd tab after pressing "Press this button to goto tab #1". Follow Max Ks answer if you would like to be able to have a button to open each specific tab.
So if I understand correctly you have a view controller outside the tabbar controller and you want to navigate to the second tab in the tabbar controller from that (outside)view controller, if that is the problem then, this is my solution and I hope it helps someone as I spent some time on this issue myself.
First connect the (outside)Viewcontroller 0 to the tabbar controller in the storyboard with modal segue and give it identifier - "showTabBar" (not as one of the tabs just a modal segue).
Then:
in Viewcontroller 0 declare:
var tabBarIndex: Int?
//function that will trigger the **MODAL** segue
private func loadTabBarController(atIndex: Int){
self.tabBarIndex = atIndex
self.performSegue(withIdentifier: "showTabBar", sender: self)
}
//in here you set the index of the destination tab and you are done
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showTabBar" {
let tabbarController = segue.destination as! UITabBarController
tabbarController.selectedIndex = self.tabBarIndex!
}
}
then you can navigate to ViewController 2 like that(don't forget it is 0 indexed):
self.loadTabBarController(atIndex: 1)
This is tested and working as of the day I am posting this answer using
Swift 3.0.2 / Xcode 8.2.1

What is a StoryBoard ID and how can I use this?

I am new to IOS developing and recently started in Xcode 4.5. I saw for every viewController that i could set some identity variables including the storyboard ID. What is this, and how can I use it?
I started searching on stackoverflow and couldn't find any explanation for it.
I assumed it's not just some stupid label that I can set to remember my controller right? What does it do?
The storyboard ID is a String field that you can use to create a new ViewController based on that storyboard ViewController. An example use would be from any ViewController:
//Maybe make a button that when clicked calls this method
- (IBAction)buttonPressed:(id)sender
{
MyCustomViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
This will create a MyCustomViewController based on the storyboard ViewController you named "MyViewController" and present it above your current View Controller
And if you are in your app delegate you could use
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
Edit: Swift
#IBAction func buttonPressed(sender: AnyObject) {
let vc = storyboard?.instantiateViewControllerWithIdentifier("MyViewController") as MyCustomViewController
presentViewController(vc, animated: true, completion: nil)
}
Edit for Swift >= 3:
#IBAction func buttonPressed(sender: Any) {
let vc = storyboard?.instantiateViewController(withIdentifier: "MyViewController") as! ViewController
present(vc, animated: true, completion: nil)
}
and
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
To add to Eric's answer and update it for Xcode 8 and Swift 3:
A storyboard ID does exactly what the name implies: it identifies. Just that it identifies a view controller in a storyboard file. It is how the storyboard knows which view controller is which.
Now, don't be confused by the name. A storyboard ID doesn't identify a 'storyboard'. A storyboard, according to Apple's documentation, 'represents the view controllers for all or part of your app’s user interface.' So, when you have something like the picture below, you have a storyboard called Main.storyboard which has two view controllers, each of which could be given a storyboard ID (their ID in the storyboard).
You can use a view controller's storyboard ID to instantiate and return that view controller. You can then go ahead to manipulate and present it however you want. To use Eric's example, say you want to present a view controller with identifier 'MyViewController' when a button is pressed, you would do it this way:
#IBAction func buttonPressed(sender: Any) {
// Here is where we create an instance of our view controller. instantiateViewController(withIdentifier:) will create an instance of the view controller every time it is called. That means you could create another instance when another button is pressed, for example.
let vc = storyboard?.instantiateViewController(withIdentifier: "MyViewController") as! ViewController
present(vc, animated: true, completion: nil)
}
Please take note of changes in syntax.

Resources