Dismiss NSViewController presented with a show segue swift - xcode

I have a NSViewController, let's name it SecondViewController (which is called by the previous NSViewController, named FirstViewController, as a modal window with a segue) that calls the other NSViewController, named ThirdViewContoller, with show segue (all segues performed programmatically: self.performSegueWithIdentifier("nameOfSegue", sender: self). When in SecondViewController I write this code:
self.dismissController(SecondViewContoller)
self.performSegueWithIdentifier("startGame", sender: self)
Everything works, but then I need to reopen SecondViewController (with a modal segue) using this code in ThirdViewController:
self.dismissController(ThirdViewController)
self.performSegueWithIdentifier("changeHardness", sender: self)
The ThirdViewController is never dismissed.
BTW, if I try to open ThirdViewController with a modal segue, it crashes, giving that:
2015-03-31 11:24:19.429 MiniGames Ultra[8074:522218] *** Assertion
failure in -[Project.SecondViewController
presentViewController:animator:],
/SourceCache/AppKit/AppKit-1344.72/Controllers/NSViewController.m:803
2015-03-31 11:24:19.429 Project[8074:522218]
presentViewController:animator:: View '''s view is not in a window/view hierarchy. 2015-03-31
11:24:19.431 MiniGames Ultra[8074:522218] (...etc)

Related

What object a menuitem action triggered segue should be called on?

I have a menuitem selection triggered segue you can see on the attached pictures
The NSMeniItem connections:
The segue it triggers:
How can I trigger the segue programmatically.
It has an identifier, it's ok.
But what object on I have to call the
(void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender;
#vadian pointed me out that I need the windowcontroller the segue should be called on first and I can get it like this
let mainStoryBoard = NSStoryboard(name: "Main", bundle: nil)
windowController = mainStoryBoard.instantiateController(withIdentifier: "Preferences") as! NSWindowController
windowController.showWindow(self)
where
windowController is a property in AppDelegate
"Preferences" is the identifier in the Storyboard
it has benefit of getting a reference to the window controller itself
as I did not need the reference currently just wanted to trigger the segue i stayed with the following solution
[NSApp sendAction:mPreferencesMenuItem.action to:mPreferencesMenuItem.target from:mPreferencesMenuItem];
where mPreferencesMenuItem is the menuitem that triggers the segue
NSViewController and NSWindowController conforms to the NSSeguePerforming protocol. So in your controller subclass you can call [self performSegueWithIdentifier:(NSString *)identifier sender:(id)sender];

How to create modal slide-out window in Mac OS?

How can I create modal slide-out window/view "in-window" in Xcode like in these screenshot?
I've tried create new Window controller with "Authentication panel style" animation but then I'm receiving only Xcode crashes.
That kind of modal window is called a Sheet. It's very easy to get this behavior with a Storyboard segue, or programmatically with an NSViewController subclass. The example below is just a blank OS X Cocoa application as created by Xcode. (I chose Swift as the language, but it will work the same way with Objective-C.)
The only things I added to the storyboard was a second View Controller for the sheet view, and a label and pushbutton on each view.
Displaying The Sheet View With A Storyboard Segue
With the Sheet View controller selected and the Connections Inspector tab displayed, connect "Presenting Segues - sheet" to the "Display Sheet" button.
Connect "Received Actions - dismissController:" to the "Close Sheet" button.
That's it! There's no code needed to make this example work; just build and run.
Displaying The Sheet View Programmatically
Note that Xcode creates the default project with two custom class files. In the Storyboard, AppDelegate.swift is represented in the Application scene:
We don't need to use the AppDelegate for this example, but you could use it for interaction with the Main Menu, or other things.
The custom ViewController.swift custom class will be used to present the sheet. It is represented in the View Controller scene:
To instantiate the Sheet View Controller programmatically, it needs a Storyboard ID. Here, we'll give it the ID "SheetViewController". Note that it's still a plain NSViewController; we don't need to make it a custom class for this example, but your application might want to:
Displaying the ViewController.swift file in the assistant editor, Ctrl-drag a connection from the "Display Sheet" button into the custom class. This will create stub code for an #IBAction function we'll name "displaySheet":
In the ViewController.swift file, we'll implement the Sheet View Controller as a lazy var. It will get instantiated only once, the first time it's accessed. That will happen the first time the displaySheet function is called.
// ViewController.swift
import Cocoa
class ViewController: NSViewController {
lazy var sheetViewController: NSViewController = {
return self.storyboard!.instantiateControllerWithIdentifier("SheetViewController")
as! NSViewController
}()
#IBAction func displaySheet(sender: AnyObject) {
self.presentViewControllerAsSheet(sheetViewController)
}
}
Swift 4 version:
// ViewController.swift
import Cocoa
class ViewController: NSViewController {
lazy var sheetViewController: NSViewController = {
return self.storyboard!.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "SheetViewController"))
as! NSViewController
}()
#IBAction func displaySheet(sender: AnyObject) {
self.presentViewControllerAsSheet(sheetViewController)
}
}
As in the first example, the "Close Sheet" button is connected to the "dismissController:" action on the Sheet View Controller. Alternatively, you could call that function programmatically from your ViewController class:
self.dismissController(sheetViewController)
For more information, refer to the Apple "Sheets Programming Topics" document:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Sheets/Sheets.html
Objective-C version:
- (IBAction)displaySheet:(id)sender {
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
}

How to transport the Spotlight API code to the view controller

I have written my Spotlight API code and it seems to be working okay. I can check it out in the spotlight but there's only one problem :
It won't take me to the desired view controller! How do I do that? I've added a
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showIt" {
let ThatVC = segue.destinationViewController as! ItThat
}
}
but it still won't take me to the right spot. Where am I going wrong?
prepareForSegue is used to notify the view controller that a segue is about to be performed (what data to prepare, confirms destination, etc). prepareForSegue is only called when a segue has already been initiated. It does not however perform the segue itself.
If your segue is unconditional, just use a standard segue in Interface Builder (pull from the UIButton to your destination scene).
If your segue is conditional, pull from the UIButton's parent scene to the destination scene in Interface Builder. Once this is finished, you can create a new #IBAction and perform a segue manually.
#IBAction func fooAction() {
performSegueWithIdentifier("showIt", sender: self)
}
Just make sure "showIt" is the segue's identifier.

Could not cast value of type UITabBarController to FirstViewController (xCode 6.4)

I'm trying to pass variables from a view controller to another one. First, there's a connection screen. When the infos are verified, then I pass the username and other data to the whole program (that has a tab bar controller).
Here is the code. I'm using Xcode 6.4. In the previous version, the page would open but the variables didn't pass. Now it just gives me the above error.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "lienConnecte") {
let nav = segue.destinationViewController as! UITabBarController // this line was just an attempt to find a solution
let vueFil = segue.destinationViewController as! FirstViewController
vueFil.utilisateur = utilisateur
}
}
Of course I know that in the storyboard, the segue points to the tab bar controller (because I need it afterwards), but I want the values to be passed to the FirstControllerView
Found the solution, for those who will see this post:
let tabBarController = segue.destinationViewController as! UITabBarController
let vueFil = tabBarController.viewControllers![0] as! FirstViewController
You cannot turn one thing into another, like some sort of magician, by saying as. You have to get a reference to the actual thing you're after. If there's a FirstViewController that is one of the child view controllers of the UITabBarController, then first get a reference to the UITabBarController (which you already know how to do), and then obtain its viewControllers property — those are its children, and you can, from there, get the one you want by its index number.
Your tab view controller is a container view controller that owns child view controllers. Presumably, FirstViewController is one of these child view controllers. Therefore, your tab view controller and your FirstViewController are different instances. You can access a tab bar's children with the viewControllers property:
let firstVC = tabVC.viewControllers?.first
// firstVC should be your FirstViewController

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