I am creating a window controller that I want to add to my Document object in the Document's makeWindowControllers function. However, after I have added this window controller, I can not resolve the windowController's Document object. This property should be set by my Document on the window controller in the addWindowController call. Any ideas as to why this might be the case?
let movieStoryboard = NSStoryboard(name: NSStoryboard.Name("MovieWindowStoryboard"), bundle: nil)
movieWindowController = movieStoryboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("MovieWindowController")) as? NSWindowController
self.addWindowController(movieWindowController)
movieWindowController.window?.performClose(self)
Related
My document-based cocoa app has a shared inspector window whose contents change depending on which document is active.
The inspector window controller is a shared singleton, instantiated form its storyboard on demand.
The document class simply creates its main window from a storyboard, and becomes the window's delegate:
class Document: NSDocument {
override func makeWindowControllers() {
let storyboard = NSStoryboard(name: "Main", bundle: nil)
guard let windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as? NSWindowController else {
fatalError("Storyboard Inconsistency!")
}
windowController.window?.delegate = self
self.addWindowController(windowController)
}
Whenever a document's main window becomes active, it adds the inspector's window controller to its own:
extension Document: NSWindowDelegate {
func windowDidBecomeMain(_ notification: Notification) {
self.addWindowController(InspectorWindowController.shared)
}
}
(this also updates the window controller's document property)
In anticipation to the case where the last document is closed, I also added:
func windowWillClose(_ notification: Notification) {
self.removeWindowController(InspectorWindowController.shared)
}
(This is only needed for the last document, since otherwise the new active document takes over and the window controller is automatically removed from the closing document once it is added to the newly activated document)
The Inspector itself overrides the property document and the method windowTitle(forDocumentDisplayName:), in order to keep up with the active document:
class InspectorWindowController
override var document: AnyObject? {
didSet {
// (Update view controller's contents)
}
}
override func windowTitle(forDocumentDisplayName displayName: String) -> String {
if document == nil {
return "Inspector - No Active Document"
} else {
return "Inspector - \(displayName)"
}
}
The problem is, when I close the last open document window, the inspector's window title stays at the (custom) title set for the last document. That is, when the inspector window controller's document property is set to nil, windowTitle(forDocumentDisplayName:) is not called.
Even calling synchronizeWindowTitleWithDocumentName() does not help, since the docs clearly mention that:
Does nothing if the window controller has no associated document or
loaded window. This method queries the window controller’s document to
get the document’s display name and full filename path, then calls
windowTitle(forDocumentDisplayName:) to get the display name to show
in the window title.
(emphasis mine)
I can reset the Inspector's content to the "No document" state; How can I do the same for the window title?
OK, I found the (silly and obvious) answer:
override var document: AnyObject? {
didSet {
// (Update view controller's contents, etc...)
if document == nil {
self.window?.title = "Inspector - No Active Document"
}
}
}
I'm not sure if this is the correct way of dealing with it, but it does get the job done.
I will accept any better answer though.
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.
Ok so here is my question.
I want to have a screen pop up right after my LaunchScreen exits and i want to be able to add information into it, however once I add that information into it, I do not want to see that screen again.
I will be using storyboard, swift and CoreData and Xcode 6.3 if that helps.
Thanks in advanece
NSUserDefaults is a really quick way of storing (small amounts of) data.
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(true, forKey: "hasSeenStartup")
if(defaults.boolForKey("hasSeenStartup")){
println("Don't show")
}
First you will need to define a set of userDefaults, easiest is standardUserDefaults()
We can set a boolean value to a key (after we showed the popup screen) using setBool() this takes 2 parameters, the first is the boolean value, the second is a key for the value.
When the users launches the app, you will need to get the boolean value for the key. If the user already has seen the popup (it’s boolean value for hasSeenStartup will be set to true) you can skip the popup and show them the other viewController
EDIT:
Since your question seems to focus on showing the new view controller rather than saving the data. Here is some code on how to show a new view controller.
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: NewViewControllerClass = storyboard.instantiateViewControllerWithIdentifier(“newViewController") as! NewViewControllerClass
self.presentViewController(vc, animated: true, completion: nil)
To use this code you will need to change the:
Storyboard name to the name of your storyboard (defaults to “Main”)
Set the class of the viewController by replacing NewViewControllerClass with the class of (obviously) your new viewController.
Change the newViewController with the Identifier
You can than use this code to present the new ViewController. Present this viewController if your Core Data has info saved about the user and thus if the user has seen the initial screen.
I would advice to retrieve the Core Data inside the ViewDidAppear method inside your FirstViewController.
override func viewDidAppear(animated: Bool) {
if (check to see if core data is not empty){
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: NewViewControllerClass = storyboard.instantiateViewControllerWithIdentifier(“newViewController") as! NewViewControllerClass
self.presentViewController(vc, animated: true, completion: nil)
}
}
I've tried to build on a Cocoa app which uses storyboard and Swift in Xcode 6. However, when I tried to alter the title of window from within NSViewController, the following code doesn't work.
self.title = "changed label"
When I wrote the above code in viewDidLoad() function, the resultant app's title still remains window.
Also, the following code causes an error, since View Controller doesn't have such property as window.
self.window.title = "changed label"
So how can I change the title of window programmatically in Cocoa app which is built on storyboard?
There are 2 problems with your code:
viewDidLoad is called before the view is added to the window
NSViewController does not have a window property
To fix the first one, you could override viewDidAppear(). This method is called after the view has fully transitioned onto the screen. At that point it is already added to a window.
To get a reference to the window title, you can access a view controller's window via its view: self.view.window.title
Just add the following to your view controller subclass, and the window title should change:
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.title = "changed label"
}
This worked for me, currentDict is NSDictionary passed from previous viewController
var currentDict:NSDictionary?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if let myString:String = currentDict?["title"] as? String {
self.title = myString
}
}
I have a Document based core data app. The main document window has a number of views, each controlled by its own custom NSViewController which are switched in as necessary. I want each of these view controllers to be able to drop down a custom modal sheet from the document window. However because the views are separate and not in the MyDocument nib I cannot link the view to the document window in IB. This means that when I call
[NSApp beginSheet: sheetWindow modalForWindow: mainWindow modalDelegate: self didEndSelector: #selector(didEndSheet:returnCode:contextInfo:) contextInfo: nil];
I’m supplying nil for mainWindow and the sheet therefore appears detached.
Any suggestions?
Many Thanks
You can use [[self view] window]
Indeed, it's self.view.window (Swift).
This may be nil in viewDidLoad() and viewWillAppear(), but is set properly by the time you get to viewDidAppear().
One issue with the other answers (i.e., just looking at self.view.window) is that they don't take into account the case that when a view is hidden, its window property will be nil. A view might be hidden for a lot of reasons (for example, it might be in one of the unselected views in a tab view).
The following (swift) extension will provide the windowController for a NSViewController by ascending the view controller hierarchy, from which the window property may then be examined:
public extension NSViewController {
/// Returns the window controller associated with this view controller
var windowController: NSWindowController? {
return ((self.isViewLoaded == false ? nil : self.view)?.window?.windowController)
?? self.parent?.windowController // fallback to the parent; hidden views like those in NSTabView don't have a window
}
}
If your controller can get access to the NSDocument subclass, you can use -windowForSheet
more about Tim Closs answer :
-(void)viewDidAppear
{
self.view.window.title = #"title-viewDidAppear"; //this only works when and after viewDidAppeer is called
}
-(void)viewWillDisappear
{
self.view.window.title = #"title-viewWillDisappear"; //this only works before and when viewWillDisappear is called
}