windowDidLoad() never called using storyboards for mac - xcode

I've just played around with the new mac storyboard-feature included in Xcode 6. I've set up a new OS X-project using storyboards and swift, then I've created a new file MainWindowController.swift, created the initializer init(coder: NSCoder!) (because otherwise the compiler warns me) and hooked everything up in the Main.storyboard file (set the MainWindowController-class for the WindowController in the inspector).
Everything compiles fine, my Window with the specified window content-view opens. But the code I've written in the windowDidLoad-function is never be called. Let it just something like:
override func windowDidLoad() {
super.windowDidLoad()
println("Executed")
}
I've also tested if my initializer is called - it is.
Does anybody has a clue? I've never used storyboards intensively on iOS before, maybe I miss something substantial.

In Yosemite, NSViewController has been promoted with powerful new features to make it work with Storyboards. Meanwhile, NSWindowController got demoted. With Storyboards, windows are no longer loaded from a nib, so windowDidLoad() doesn't get called anymore.
It makes sense for the window itself to become less important, in favor of a more powerful view it actually contains. My other answer on this page shows how to set up an AppDelegate to customize the window appearance. There's more detail on another page here, about using an AppDelegate to implement some of the things you might previously have done in an NSWindowController.
However, if you only wanted to catch windowDidLoad() as a way to customize the appearance options of the window, it is very easy to do that in Interface Builder, by simply adding them as User Defined Runtime Attributes to the NSWindow object. You don't need to subclass NSWindowController or write any code at all. Just plug in these values to the NSWindow object via the Identity Inspector pane to achieve the same effect shown in the AppDelegate example code:
Keypath: titlebarAppearsTransparent, Type: Boolean, Value: Checked
Keypath: titleVisibility, Type: Number, Value: 1
Keypath: styleMask, Type: Number, Value: 32783
Look in the headers to determine the actual numeric values of the constants.
( for example: NSWindowTitleVisibility.Hidden = 1 )
Of course, you can't specify individual bits of the styleMask, but it's easy enough to add them all together and get a single number to specify the style.

Remove everything except the Application scene from the Main.storyboard file, and instead, create a new Application.storyboard for the application window. Implement an application delegate class and connect it to the Application object in Main.storyboard. Use this class to instantiate the window controller and set up custom options for the application window.
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidBecomeActive(notification: NSNotification) {
let storyboard = NSStoryboard(name: "Application", bundle: nil)
applicationController = storyboard.instantiateInitialController() as? NSWindowController
if let window = applicationController?.window {
window.titlebarAppearsTransparent = true
window.titleVisibility = NSWindowTitleVisibility.Hidden
window.styleMask |= NSFullSizeContentViewWindowMask
applicationController!.showWindow(self)
}
}
}
Rather than subclassing NSWindowController, use the ViewController.swift subclass of NSViewController that Xcode creates for you automatically with the project.
In the storyboard, notice how there's a Relationship that connects the "window content" to the ViewController. So, the ViewController can now do things that you might previously have done in a window controller.
The ViewController.swift file will already have a default override of viewDidLoad() that will be called when the window loads, just as you were expecting windowDidLoad() to be called if it were an NSWindowController subclass.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
println("Executed")
}

Related

OS X storyboard calls viewDidLoad before applicationDidFinishLaunching

I created a Mac OS X application in Xcode using storyboards. For some reason the applicationDidFinishLaunching method in the AppDelegate is being called after viewDidLoad in the NSViewControllers. As with iOS apps, I thought viewDidLoad is supposed to be called before applicationDidFinishLaunching? Do storyboards in OS X apps initialize the view controllers before the app has finished launching?
I am using the applicationDidFinishLaunching method to register default settings into NSUserDefaults. Unfortunately, registering the default values is happening after the views in the storyboard are loaded. Therefore, when I set up the view in each view controller using viewDidLoad, the defaults data in NSUserDefaults has not been set. If I can't use applicationDidFinishLaunching to register NSUserDefaults in OS X storyboard apps, then how I set the defaults before viewDidLoad is called?
To fix this issue, in the Main.storyboard in Xcode, I turned off "Is Initial Controller" for the main window. I assigned a storyboard ID to the main window as "MainWindow". Then in the AppDelegate I entered the following code:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
let storyboard = NSStoryboard(name: "Main", bundle: nil)
let mainWindow = storyboard.instantiateControllerWithIdentifier("MainWindow") as! NSWindowController
mainWindow.showWindow(nil)
mainWindow.window?.makeKeyAndOrderFront(nil)
}
}
The app does not crash but now the window never appears. The following image displays the storyboard I'm working with:
Correct, the lifecycle is a wee bit different in OS X.
Instead of letting the storyboard be your initial interface (this is defined in the General settings of your project), you can instead set up a MainMenu xib file and designate that as your main interface, then in your applicationDidFinishLaunching method in your AppDelegate you can programmatically instantiate your storyboard after you have completed your other initialization code.
I recommend checking out Cocoa Programming for OS X: The Big Nerd Ranch Guide if you haven't already; one nice thing they do in their book is actually have you get rid of some of the default Xcode template stuff and instead they have you set up your initial view controller the "right" way by doing it explicitly.
You might put something like this in your applicationDidFinishLaunching:
NSStoryboard *mainStoryboard = [NSStoryboard storyboardWithName:#"Main" bundle:nil];
MyWindowController *initialController = (MyWindowController *)[mainStoryboard instantiateControllerWithIdentifier:#"myWindowController"];
[initialController showWindow:self];
[initialController.window makeKeyAndOrderFront:self];
This assumes that you've already changed "Main Interface" to something like MainMenu.xib.
As the question's author mentioned:
The app does not crash but now the window never appears.
Despite Nicolas and Aaron both helpful answers (I already adquire the book you recommended, Aaron, and will start implementing the two-storyboard pattern your way, Nicolas), neither solve the specific problem of the window not showing.
Solution
You need make your WindowController instance live outside applicationDidFinishLaunching(_:)'s scope. To accomplish it, you could declare a NSWindowController propriety for your AppDelegate class and persist your created WindowController instance there.
Implementation
In Swift 4.0
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var mainWindowController: NSWindowController?
func applicationDidFinishLaunching(_ aNotification: NSNotification) {
let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
let mainWindow = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "MainWindow")) as! NSWindowController
mainWindow.showWindow(self)
mainWindow.window?.makeKeyAndOrderFront(self)
// After applicationDidFinishLaunching(_:) finished, the WindowController instance will persist.
self.mainWindowController = mainWindow
}
}
In addition to Aaron's answer, I found out that the separate Interface Builder file containing the menu alone (separate from the window and view controller) does not need to be a xib; it too can be a storyboard. This enables us to easily fix as follows:
Duplicate your original storyboard (Main.storyboard) and rename it to "Menu.storyboard"
Delete the window controller and view controller from Menu.storyboard
Delete the app menu bar from Main.storyboard.
Change your app target's "Main Interface" from "Main.storyboard" to "Menu.storyboard".
(I tried it in my app and it works)
This avoids having to re-create the app's main menu from scratch, or to figure out how to transplant your existing one from "Main.stroyboard" to "Menu.xib".
The other solution is registering NSApplicationDidFinishLaunchingNotification in your view controllers and move your code from viewDidLoad to applicationDidFinishLaunchingNotification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidFinishLaunchingNotification:)
name:NSApplicationDidFinishLaunchingNotification
object:nil];
Based on my previous answer here
If you want a piece of code to be run before everything, you can override the AppDelegate's init() like this:
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
override init() {
DoSomethingBeforeEverthing() // You code goes here
super.init()
}
...
}
Few points to remember:
You might want to check, what's allowed/can be done here, i.e. before app delegate is initialized
Also cleaner way would be, subclass the AppDelegate, and add new delegate method that you call from init, say applicationWillInitialize and if needed applicationDidInitialize

NSCollectionView does not hide in osx

I used NSCollectionView in my application. In certain condition i want to hide and Unhide the NSCollectionView. But it will not hide the NSCollectionView.
I used the following code
#IBOutlet weak var thumbnailView: NSCollectionView!
func applicationDidFinishLaunching(aNotification: NSNotification) {
thumbnailView.hidden = true
NSThread.sleepForTimeInterval(5)
thumbnailView.hidden = false
}
Note: Sleep the thread just for demonstration purpose
Also Hiding the NSScrollView is not working.
EDIT: I perform same code on Button Touch up Inside event i get the same result. It does not hide my CollectionView.
#IBAction func ButtonnISClick(sender: AnyObject) {
thumbnailView.hidden = true
NSThread.sleepForTimeInterval(5)
thumbnailView.hidden = false
}
Here are things that are wrong with your code (mostly because you did not provide enough information in your question):
Use lowercase strings when naming variables (so change ThumbnailView to thumbnailView;
I don't know where are you writing this code. Is it NSWindowController, NSViewController or NSWindow subclass? Depending on the location, you should write 2nd to 4th lines in different methods (either windowDidLoad(), viewDidLoad() or awakeFromNib()
Update: Given your code is in application did finish launching and you are sleeping in that method, you won't see any changes, since the window of your app is presented only after the method has returned (i.e. all code has been executed). I suggest you to move this code into a subclass of either NSWindowController's windowDidLoad (I'm not sure about that one) or NSViewController's viewDidAppear: method.

IBOutlet is nil, but it is connected in storyboard, Swift

Using Swift 1.1 and Xcode 6.2.
I have a UIStoryboard containing a singular, custom UIViewController subclass. On it, I have an #IBOutlet connection of type UIView from that controller to a UIView subclass on the storyboard. I also have similar outlets for subviews of that view. See figure A.
But at run time, these properties are nil (Figure B). Even though I have assured I've connected the outlets in Interface Builder.
Thoughts:
Is it possible that because I am using a subclass of a subclass something messes up with the initialization? I am not overriding any initializers
awakeFromNib: is not getting called for some reason
Maybe it doesn't connecting to subviews on subviews
Things I have tried:
Matching #IBOutlet and storyboard item types exactly (instead of UIView)
Deleting property and outlet and re-added them
Figure A*
Figure B
*The obscured code in Figure A is:
#IBOutlet private var annotationOptionsView: UIView!
#IBOutlet private var arrivingLeavingSwitch: UISegmentedControl!
Thank you.
Typically this happens because your view controller hasn't loaded its view hierarchy yet. A view controller only loads its view hierarchy when something sends it the view message. The system does this when it is time to actually put the view hierarchy on the screen, which happens after things like prepareForSegue:sender: and viewWillAppear: have returned.
Since your VC hasn't loaded its view hierarchy yet, your outlets are still nil.
You could force the VC to load its view hierarchy by saying _ = self.view.
Did you instantiate your view controller from a Storyboard or NIB, or did you instantiate it directly via an initializer?
If you instantiated your class directly with the initializer, the outlets won't be connected. Interface Builder creates customized instances of your classes and encodes those instances into NIBs and Storyboards for repeated decoding, it doesn't define the classes themselves. If this was your problem, you just need to change the code where you create your controller to instead use the methods on UIStoryboard, or UINib.
Have you tried running Product > Clean. Solved a very similar problem for me.
The storyboard wasn't recognizing any further UI things I added to it. At run time all the references were nil. So I cleared my derived data folder and then those connections worked again.
This happened for me because I was accidentally instantiating my view controller directly instead of instantiating it through the storyboard. If you instantiate directly via MyViewController() then the outlets won't be connected.
This was happening to me with my custom collection view cell. Turns out I had to replace my registerClassforReuseIdentifier method with registerNib. That fixed it for me.
In my case, it happened because I overriden the loadView method in my ViewController subclass, but forgot to add [super loadView]
-(void)loadView {
// blank
}
When you override the loadView method, the it is your responsibility to init your subviews. Since you override it, the views from interface builder do not get the chance to convert to cocoa objects and thus outlets remain nil.
If you implement loadView in your view controller subclass, then it becomes your responsibility load the UI elements from from storyboard/xib into code.
Or just call
[super loadView];
So that the superclass gets the chance to load storyboard/xib into code.
If you instantiate view controller through programmatically. Then
try creating it like below
let initialVC = self.storyboard?.instantiateViewController(withIdentifier: "InitialVC") as! InitialVC
instead of directly
let initialVC = InitialVC()
This worked for me.
You can call controller.view to force to load the view to initialize the IBOutlets, then you will be able to assign the values.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "identifier") {
let controller = segue.destinationViewController as! YourController
let _ = controller.view //force to load the view to initialize the IBOutlets
controller.your_IBOutlet_property = xxx
...
controller.delegate = self
}
}
I encounter this problem recently! Here is my thought.
The problem is not about you storyboard or any link issue. It is about how you initiate your ViewController. Especially when you are using Swift.(There is barely nothing in the editor when you create a class file)
By simply using the init() from super class can not initiate anything you worked with story board. So what you need to do is changing the initialisation of the ViewController. Replace
let XXViewController = XXViewController()
by
let XXViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("XXViewController") as! XXViewController
This tells the program to go to the storyboard find XXViewController and initiates all IBOutlet in your storyboard.
Hope this help~ GL
For me, this occurred when I accidentally declared my view controller's class as
class XYZViewController: UINavigationController {
}
(ie as a UINavigationController not a UIViewController).
Xcode doesn't pick up on this mistake, the class seems to build fine, and override functions such as viewDidLoad, viewWillAppear, etc. all work correctly. But none of the IBOutlets get connected.
Changing the declaration to
class XYZViewController: UIViewController {
}
fixed it completely.
2019, ONE POSSIBILITY FOR THIS HORRIBLE PROBLEM:
Say you have perhaps a container view that shows some sort of clock. So you have
class Clock: UIViewController
You actually use it in a number of places in the app.
On the main screen, on the details screen, on the edit screen.
You have a complicated snapchat-like modern app.
In fact, Clock may actually be loaded more than once at the same time somewhere on the same screen. (Maybe it's hidden in some cases.)
You start working on one instance of Clock on one of your many storyboards.
On that storyboard you add a label, NewLabel.
Naturally you add the outlet in code. Everything should work. All the other outlets work perfectly.
You have definitely linked the outlet.
But the app crashes with NewLabel as nil.
Xcode clearly tells you "you forgot to connect the outlet".
The reason is this .......... you have "NewLabel" on only one of the storyboard uses of Clock!
The crash is actually from >>> an other place <<<< you are using Clock!!!!
Xcode does not tell you the crash is from another place altogether, not from where you are working!
The crash is actually not from the place you are working - it's from another storyboard, where there is no "NewLabel" item on that storyboard!!!
Frustrating.
For Swift 3.
func configureView() {
let _ = self.view
}
In my case, the app started crashing all of a sudden.
Debugging it revealed that all outlets were still nil at the time of viewDidLoad().
My app still uses nibs (not storyboards) for most view controllers. Everything was in place, all outlets wired properly. I double-checked.
We typically instantiate our view controllers as
let newVC = MYCustomViewController()
...which for some reason seems to work as long as the .xib is named the same as the view controller class (not sure how that works, though. We are not calling init(nibName:bundle:) with nil arguments, or overriding init() to do so on self like it is typically suggested...).
So I tried to explicitly call
let newVC = MYCustomViewController(nibName: "MYCustomViewController", bundle: .main)
...only to be greeted with the runtime exception error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/nicolasmiari/Library/Developer/CoreSimulator/Devices/3DA3CF21-108D-498F-9649-C4FC9E3C1A8D/data/Containers/Bundle/Application/C543DDC1-AE86-4D29-988C-9CCE89E23543/MyApp.app> (loaded)' with name 'MYCustomViewController''
And then, I saw it:
The "Target Membership" checkbox of the .xib file was unchecked.
Must have happened when resolving one of the frequent merge conflicts regarding the Xcode project file.
Apple definitely needs to come up with a project file format that is more SCM-friendly.
You need to load the view hierarchy first in order to instantiate the outlets in the storyboard. For this, you can manually call the loadView or loadViewIfNeeded methods.
100% Working solution for creating ViewControllers from XIB without StoryBoards
Create class CustomViewController : UIViewController
Create view CustomViewControllerView.xib
In CustomViewControllerView.xib in Interface Builder select Placeholders -> File's Owner
In "Attributes inspector" set Class to CustomViewController
In "Connections inspector" connect "view" to top-level view of xib (ensure top-level view's Class is not pointing to CustomViewController)
In "Connections inspector" connect other outlets (if needed/exist)
Create an instance of CustomViewController in parent view controller/App delegate
7.1.
// creating instance
let controller = CustomViewController()
7.2.
// connecting view/xib with controller instance
let bundle = Bundle(for: type(of: controller))
bundle.loadNibNamed("CustomViewControllerView", owner: controller, options: nil)
7.3.
// get/set outlets
controller.labelOutlet.text = "title"
controller.imageOutlet.image = UIImage(named: "image1")
Check your IBOutlet connection if it connected to the File owner or the view.
There could be mistakes.
Other case:
Your outlets won't get set until the view controller's view is actually instantiated, which in your case is probably happening shortly after initWithNibName:bundle:—at which point they'll still be nil. Any setup you do that involves those outlets should be happening in your view controller's -viewDidLoad method.
For me, I had same error on a localized storyboard, an element was added in some locale and not in the other, so I had null reference for that element when switched to the missing element locale, I had to remove (redundant) localization for that storyboard using https://stackoverflow.com/a/42256341/1356559.
For me, this was crashing because containerView was nil.
Here is my code with Crash.
#IBOutlet private var containerView: UIView! // Connected to Storyboard
override open func loadView() {
containerView.addSubview(anotherView)
}
The missing thing was calling the super.loadView(). So adding it solved problem for me.
Fixed Code:
#IBOutlet private var containerView: UIView!
override open func loadView() {
super.loadView()
containerView.addSubview(anotherView)
}
I had a similar issue when I had previously added register(_:forCellReuseIdentifier:) for the custom cell after I had already defined the identifier in the storyboard. Had this code in the viewDidLoad() function. Once I removed it, it worked fine.
Yet another case I just ran into. I changed the name of my class for the UIViewController, but I forgot to change the name of the .xib file where the interface was built.
Once I caught this and made the file names reflect the class name, it was all good!
I hope that helps someone.
Got one more ...
If you have a custom class for a UITableViewCell but forget to specify Custom in the Style of the cell.
Check to see if you have any missing or disconnected outlets.
You can validate if the is view is loaded.
if isViewLoaded && view.window != nil {
//self.annotationOptionsView.
}
select both .h and .m view controller files
remove the reference of those files
re-add the files to your project tree
open the storyboard, eventually re-build the project
Accidently I subclassed my view controller with AVPlayerViewController instead of UIViewController. By replaying it to UIViewController things back normal. This should help.
No build cleaning (normal&full), removing derived data folders and quitting Xcode worked for me.
I had the same problem after copying a class (linked to a xib) to reuse it with another viewcontroller class (linked to a storyboard).
I forgot to remove
override var nibName
and
override var nibBundle
methods.
After removing them, my outlets started to work.
I see you use ViewController!? in ViewController class you must use -viewDidLoad, not -awakeFromNib, -awakeFromNib use for UIView class
If you have two main.storyboards and you are making changes to the wrong one this can happen. This can happen anytime you connect an outlet from an uninstantiated storyboard.

How to use NSToolBar in Xcode 6 and Storyboard?

I've been trying to build on a Cocoa app that uses Swift and Storyboard in Xcode 6, but how can I use NSToolbar there?
In Xcode 5 and xib, you can add NSToolbar from within Object Library to any .xib files and then click on the added toolbar to expand it and drag and drop a connection from any items there to a AppDelegate.h file. In this way you can create a IBAction or IBOutlet connection. I confirmed that this can also be done if you use Swift and non-storyboard in Xcode 6. However, it looks like this is not the case in Xcode 6 and Storyboard environment.
I first created a project that uses Storyboard in Xcode 6, but then, I wasn't able to add a NSToolbar from within Object Library to a View Controller in Storyboard. So I added it to Window Controller's Window object in Storyboard. However, in this way I cannot create those connections from any items in the expanded toolbar to either AppDelegate.swift or ViewController.swift.
So my question is:
Is it feasible to create a storyboard app that uses NSToolbar?
If it is feasible, is the addition of NSToolbar to the Window Controller the proper way to use NSToolBar in Storyboard?
Finally, how can I create #IBOutlet and #IBAction connections there?
UPDATE
I found that the accepted answer by #GeorgeVillasboas only works for #IBAction. I am still looking for how to create an #IBOutlet connection...
I had this very same problem.
The solution works for both Objective-C and Swift projects.
Working with Storyboards on OSX, it creates an instance of NSWindow and segues to another NSViewController as its Window Content Segue, as you described.
On your ViewController, create a standard IBAction to receive the action when the toolbar is clicked. To wire it up with the NSToolbar, just control-drag (or leftClick-drag) from your NSToolbarItem to the FirstResponder object, as shown on the picture below.
This will open a HUGE list of available connections. Your IBAction will be on that list.
Just selected it and you're good to go.
Hope this helps!
Here's an answer that doesn't rely on run-time hook-ups - #cdalvaro's answer gets most of the way there for some applications, but isn't full, and it requires the ViewController to know about the artificial NSWindowController, which doesn't feel right.
Like #cdalvaro, the first step is to build your own subclass of NSWindowController, and to set the Storyboard WC to that class. You can then create all of your connections to and from the NSToolbar (both #IBOutlets & #IBActions) in the new WindowController. So far so good.
The last step, which I haven't seen anywhere else, is how to refer to the ViewController in the WindowController - you can't create an #IBOutlet to it - for the same reasons that we got here in the first place - you can't create references across scenes in the Storyboard. However, the WindowController must have a reference to the ViewController, and it does... self.window!.contentViewController! as! ViewController
Here's a complete WindowController with a checkbox that sets values in the ViewController, without the ViewController having to know anything...
class MyWindowController: NSWindowController {
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
#IBOutlet weak var aSwitch: NSButton!
#IBAction func toolbarActionA(sender: AnyObject) {
println("toolbarActionA")
self.viewController.a = !self.viewController.a
self.aSwitch.state = self.viewController.a ? NSOnState : NSOffState
}
}
This helped me for the IBOutlet solution you are looking for:
https://stackoverflow.com/a/27555237/3398062
Update (explanation)
I discovered this thread because I was trying to create a Circular Progress Indicator inside the toolbar and I didn't know how to animate it from the ViewController since the IBOutlet was declared inside a custom WindowController.
Finally, I found the post that I have added above which describes how to access to IBOutlets from other classes.
In essence what I have done is the following:
Create a custom NSWindowController subclass (CustomWindowController) for the Window Controller so I can add the IBOutlet for the ProgressIndicator:
Code Example:
#interface CustomWindowController : NSWindowController
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#end
Then in the ViewController class, in the method I want to use to update the state of the Progress Indicator, I create and object of the custom Window Controller.
Code Example:
CustomWindowController *customWindowController = self.view.window.windowController;`
Finally, to change the state of the Progress Indicator there is only to call the method from the created custom object.
Code Example:
[customWindowController.progressIndicator startAnimation:sender];
or
[customWindowController.progressIndicator stopAnimation:sender];
This video helped me how to create a toolbar without writing a single line of code: https://www.youtube.com/watch?v=XSQocHG3IjA
You can add the 'Window Controller' item from the Object Library (if you don't have one), connect to a View Controller (where you want your toolbar to display) and follow the video! For custom Toolbar buttons add 'Image Button' item to the Toolbar just by dragging from the Object Library. Then you can pick an image for a button, set the size and so on...
Here is a general solution for the outlets and actions. it allows you to preform all the the same functions as an iboutlet would for a tool bar item and also allows you to set the button to a function instead of creating an ibaction. hope it helps :P
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
Here is a link to my question attempting to get a cleaner answer
http://www.stackoverflow.com/questions/27371439/use-nstoolbar-outlet-xcode-6-and-storyboard/27374449
but it looks like from the answers i have gotten so far this is the best option.
The same problem of IBOutlets also applies to KVO. One of the features of the NSSplitViewController is the canCollapse property for each split view item which supports KVO, but this is unusable in IB just like IBOutlets.
The only workaround I can see is to add a NSObjectController to each scene and when the scene loads, set the object controller's object to the object in the other scene (already loaded) that you want to reference.

Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder) error in Cocoa and storyboard

I've tried to build a sample Cocoa app on which I want to connect UI components put on storyboard to ViewController.swift as either an IBOutlet or IBAction. However, when I tried to control-drag the UI components on storyboard (such as NSButton) to ViewController.swift and create a #IBAction method, and then run the app, the resultant app logs the following message in console and of course the app doesn't respond to me tapping the button.
Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder): missing setter or instance variable
How can I use the IBAction method properly?
For your information here's my ViewController.swift:
import Cocoa
class ViewController: NSViewController {
#IBOutlet var txtTitle : NSTextField
#IBOutlet var boxColor : NSBox
override func viewDidLoad() {
super.viewDidLoad()
}
func colorChanged(cp: NSColorPanel) {
let c:NSColor = cp.color;
self.boxColor.fillColor = c
}
#IBAction func btnSetColor(sender : AnyObject) {
let cp:NSColorPanel = NSColorPanel.sharedColorPanel()
cp.setTarget(self)
cp.setAction("colorChanged:")
cp.orderFront(nil)
}
#IBAction func btnSetWindowTitle(sender : AnyObject) {
if self.txtTitle.stringValue != "" {
println(self.title)
println(self.txtTitle.stringValue)
self.title = self.txtTitle.stringValue
}
}
}
I use Xcode 6 beta on OS X 10.10 Yosemite. And started the template with storyboard being on.
While the answer above correctly states that this isn't the reason for compilation issues, I thought that I would clarify for those who are just looking to eliminate the warning messages altogether. This was what I was looking for when I found this page.
When you are building your actions and some of the actions change, or get deleted in the storyboard, the outlets remain. Select the controller/window where the older unused actions used to be and you will still see them in the outlets segment of the storyboard within the attributes tab. Remove those old actions/outlets there and then the warning disappear.
Look for duplicates between the ViewController and the File's Owner. One or both might be holding on to these objects when they shouldn't be. Removing those will remove these soft warnings.
Failed to connect (storyboard) outlet from (NSApplication) to (NSNibExternalObjectPlaceholder): missing setter or instance variable
The IBAction methods working like it should, see Apple Dev Forums:
"This is a known issue ... The messages are harmless and do not
indicate a problem with your code."
Apple Dev Forums: OS X Storyboard failure
Thats not why your code is not working, you need to fix the following:
A) Here is my working code to set the title - using self.view.window.title instead self.title:
#IBAction func btnSetWindowTitle(sender : AnyObject) {
if self.txtTitle.stringValue != "" {
println(self.view.window.title)
println(self.txtTitle.stringValue)
self.view.window.title = self.txtTitle.stringValue
}
}
B) In Interface Builder you need to set NSBox "Box Type" to "Custom":
And that's it:
I think I figured out the right solution.
1) Drag an Object into you xib interface.
2) Click the Object in the left list you just dragged in.
3) Bind the Object to your custom class.(Here my class is a login window controller as example)
4) Ctrl drag button to the source code. In the popup window, choose your class name(here in example is Login Window Controller) rather than File's Owner.
Hope this could help you.
I've found another easier solution these days while coding.
Check this out.
1) Select File's Owner in Document Outline in the .xib file.
2) Specify the class you want the .xib file to connect with.
3) Now when you connect outlet to the source file, just use default File's Owner. Much easier.
4) I guess it's not enough so far. I've met an exception when running called 'loaded the 'xxx' nib but the view outlet was not set'. We should do something more.
Select the view in Document Outline. Drag from the circle of New Referencing Outlet to the File's Owner in Document Outline.
Alright, that's the new easier solution. No additional objects should add into the xib. If it doesn't work, leave comments below.

Resources