Control-drag to AppDelegate only - xcode

Xcode 6.1, OSX not ios, allows me to Control-drag from a button in MainMenu.xib to AppDelegate only. This is unfortunate for me because my IBAction must include view methods like [self setNeedsDisplay:YES] . I need to Control-drag it into my MyView file, which will tolerate them. This also makes more sense.
Control-dragging from the button to any file other than AppDelegate does nothing.
Identity Inspector > Class is set to MYView.
How can I make this work, and how does the fix work?
Also, why is it now restricted to AppDelegate? Perhaps a timing issue?
Thanks ahead,
Nick

Try dragging an empty object from the object library to the area where you see 'AppDelegate' then selecting it and setting its' class to 'MyView' then secondary dragging to that object to create the IBAction.

Related

NSToolbar in Xcode 7 using Storyboards (NSWindowController -> NSSplitViewController)

Hi I've seen this question asked a few times already but with no definite answer yet so I created it for xcode 7 and swift2 (which may have changed things a bit anyway).
I created a project using Xcode 7 and Cocoa OSX Story boards + swift2, so my project started with a NSWindowController that Connects to a NSViewController (as expected!). I added a NSToolbar to my window controller and added a NSButton to the toolbar. I changed my NSViewController to be one of the new NSSplitViewController that links to three NSViewControllers and displays their views horizontally - with vertical dividers - (similar to the layout you see in the photo app or pages in Yosemite +). My final goal will be that the button in My toolbar shows and hides the first split.
It is my understanding is, and I would expect that to achieve this I should create an action in the NSSplitViewController that changes the auto layout constrains more or less in the way they are working it out here: How to do collapse and expand view in mac application?.
And then somehow link this action to the NSButton that is in the Toolbar... which happens to be in the NSWindowController (far up and isolated in the hierarchy)...
I have already gone through other questions about NSToolbar and storyboards and failed to accomplish my goal:
The YouTube video: Cocoa Programming L17 - NSToolbar which is the closest I found to solve the problem, but his method does not work for storyboards, only creating your own xib file.
In this question: How to use NSToolBar in Xcode 6 and Storyboard? One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...). A second person suggested to create a view controller variable in the NSWindowController and manipulate its properties from there... but again, a bit dodgy too.
One latest comment I saw in that question which seems the best way to tackle the problem (but still not as good as I guess it could be) is to add a NSObjectController to the dock of each scene and when the scene loads, set the values of the objects to the other secene's controller. Is this really the best way to go ahead? If so, how could I achieve this one?
Apple did mention (again) in WWDC15 that they created storyboards for osx and the split-view controller that owns view-controllers so that you can move your logic and work to the specific view-controller, so I would be expecting to do everything from inside my split-view controller as this is the target that needs to change.
Does anyone know how to achieve this from the view controller itself? I really haven't been able to find a way to connect my ToolBarItem to it.
OK, I've created this question quite a few days ago and no answer so far so I've answer with what I recently did to overcome the problem.
After I created my Xcode project I did this:
Created a subclass MySplitViewController for the NSSplitViewController
Added an IBOutlet for each NSSplitViewItem. For example:
#IBOutlet weak var mySplitViewItem: NSSplitViewItem!
Created a subclass WindowController for the NSWindowController
Added an IBAction in the WindowController class that links to the NSToolbarItem (my button)
Added a property that gets the Window Controller's content as MySplitViewController
var mySplitViewController: MySplitViewController {
return self.window?.contentViewController as! MySplitViewController
}
Now I can access the split view controller's property from the Window Controller in the action I created:
mySplitViewController. mySplitViewItem.collapsed = true
I created some sample code that does this (but using a view controller and changing the text for a label here, just in case someone wants to see a working project with this behaviour. And a blog post about it too :)
One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...).
I think this first responder method is actually the proper way.
As an example:
Add something similar to the following, in whichever view controller makes sense.
#IBAction func doSomething(_ sender: AnyObject?) {
print("Do something.")
}
This will magically show up in the first responder:
In your storyboard, right-click the orange "first responder" icon above your window controller, and you should see doSomething in the very long list. You just need to connect that up to your toolbar button.
In the following screen capture, you can see my "Toggle Sidebar" button is connected to the toggleSidebar action in my first responder.
I didn't even have to write this method — it's provided by NSSplitViewController:
#IBAction open func toggleSidebar(_ sender: Any?)
So, I was working this same issue and finding no solution as you experienced. I read your post and was trying to figure how I would implement your solution when it occurred to me to use a notification. In about 30 seconds, I had a perfectly fine working solution:
In your windowController add an IBAction to post a notification like so
-(IBAction)toggleMasterViewClicked:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:nil];
}
Hook up that action to your NSToolbarItem, then in the viewController add self as an observer for that notification like so
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(toggleMasterView:) name:#"TestNotification" object:nil];
In your case, selector would be updateMyLabelText
I don't really see any downside here. No reference to other objects needed, no dependancies. Works flawlessly for me
While connectiong IBActions works by using either the First Responder or by adding an "Object" to the scene, then changing its class to the window's view controller class, this doesn't help with IBOutlets and delegates that you'd like to point to the view controller.
Here's a work-around for that:
Add the Toolbar to the View Controller, not to its Window. That way, you can make all the IBOutlet connections in the View Controller Scene easily. I've done that for years and found no issues with it, even when using Tabs.
You'll have to assign the window's toolbar in code, then. E.g. like this:
#interface ViewController ()
#property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
#end
- (void)viewWillAppear {
[super viewWillAppear];
self.view.window.toolbar = self.toolbar;
}

Swift class to interact with Interface Builder via IBOutlet

Good evening all,
I'm slowly working through my first OS X app. I have been having a hard time getting my Swift class to interact with an NSPopUpButton. Just to make sure I was doing it right, I created a new project and successfully erased all entries and entered text into the NSPopUpButton via AppDelegate. However, as soon as I try to move the same functionality to my own class, I can't even get the IBOutlet connection across to the new class.
Is a particular subclass type required of a new class to work properly with interface builder?
Here is a screenshot of the class I have created, as well as AppDelegate where I am trying to call the function belonging to this class.
Finally, here is the IB element in question, should I be able to select my own class under the 'Custom Class' inspector?
I am an iOS developer, but I would imagine the same principles would apply to your situation.
A ViewController class and an interface created in interface builder are two seperate things. While it may appear that they are connected via an iboutlet, they are actually independent and one can be instantiated without the other.
Currently, you are only creating an instance of your ViewController class in your App Delegate - and that's all. The system has no idea that your xib even exists! The outlets will only be connected once your app connects your xib to your ViewController class.
How do we do this? It's actually quite simple. Instead of instantiating our view controller like this:
let viewcontroller = ViewController()
We would connect our view controller to our xib in the instantiation:
let viewcontroller = ViewController(nibName: "MainWindow", bundle: NSBundle().mainBundle)
The nibName is telling the system the file name of your xib, and the NSBundle().mainBundle is telling the system where to look for the xib.
This will all only work if your xib has been assigned a custom class, like you mentioned. In your xib in interface builder, select the entire view controller. Then, in the custom class inspector type in the name of your ViewController class (in your case: ViewController - it should autocomplete). This will make sure your outlets are connected.
And you should be set up!! Let me know if you have any more problems come up.
Good luck!
EDIT:
This replaces the first part of my answer, however the part about hooking things up in Storyboard remains true. Upon reconsidering, I've believe I've realized that we are only creating the view controller, and not adding it to our view. Despite this, I believe we can take a short cut solution by adding one method to your view controller subclass (the one we set in the Storyboard). Start typing in viewDidLoad, and it should autocomplete. Type in super.viewDidLoad() at the beginning of the method. After that, type self.listUpdate(). This should work if the classes are hooked up correctly in Storyboard. This means you can delete the variables you created in the App Delegate.
Reference: You might also find Apple's documentation on creating a view controller handy (it's in Objective C online, but can be easily converted to Swift - it's the concept that counts): NSViewController Class Reference

Is there a way to set referencing outlet in Interface Builder without Ctrl-Drag

So I'm just trying to create a very simple app for demo purposes here:
Created a Single View Application, using storyboards
Added a UIView to the storyboard
Added the following code to my controller's header file:
#property (weak, nonatomic) IBOutlet UIView *myView;
Now, I understand that I can link the UIView to the controller by:
arranging my code such that the header file is next to the storyboard
holding down Ctrl key and dragging it to the property in the header file
My question is this: can I do this without Ctrl-drag? And if so, how?
More specifically - it's annoying to have to put both my header file and storyboard on screen at the same time, and it seems there should be a way to make this connection without doing so.
I also understand that I can manually place the view by creating it inside my controller's viewDidLoad function, but I'd really like to use the interface builder to simplify / visualize things.
Edit: Is the answer to my question affected whether I use storyboards or xib/nib files? (I'd switch to use the one where it works)
you should be able to right click the element, and drag the "referencing outlet" item to the view's "File's Owner" in interface builder. There, it will give you a list of all available IBOutlets (matching the object's type).
In addition to Dima's answer, you can just as well use the Connection inspector in the Utilities pane

Can I use NSViewController to provide a reusable NSTableView with defined columns and data?

I'm fairly new to Xcode and Cocoa development, so please excuse me if I use the wrong terminology.
I have a window which has an NSTableView bound to a NSArrayController. The NSTableView has some predefined columns and the NSArrayController is populated with data when my window is loaded.
This all works fine, but I now need to re-use the functionality in a number of other windows.
After much reading I think and NSViewController is what I need, to provide an object that I can re-use in different windows in multiple .xib.
So what I have done is created a new NSViewController sub class in Xcode which also created a new xib for that controller.
The xib contains a custom view, where I have placed my NSTableView.
#interface KeyViewController : NSViewController
#property (weak) IBOutlet NSTableView *keyTable;
#end
The files owner class is set to the KeyViewController, and the view outlet is set to the files owner.
I then placed a ViewController object into the original window and hooked up the view to a new custom view in the window
I then set the nib name for the ViewController in its properties.
The new view never gets displayed and the view controller initWithNibName never gets called.
Am I missing something vital or missing the plot completely. Should you be able to do this just with interface builder or do I need to alloc and init the view in code?
If I do have to do it in code, whats the purpose of the ViewController object in IB and the Nib Name property for it?
Thanks..

Code Pattern: Loading TabBarController objects directly from independent .xib file (instead of from MainWindow.xib)

I've looked around online, and haven't been able to find an acceptable solution to this problem...
I'm looking for a simple code pattern:
Load a TabBarController object (with associated subview controllers) from a separate .xib file, instead of including and loading automatically from a default MainWindow.xib.
In XCode terms, starting from a new iPad/iPhone project as a "Tab Bar Application", the goal is to solve the following:
Create the project
Move: TabBarController, TabBar, FirstViewController, and SelectedSecondViewController from MainWindow.xib, into a new "TabBarController.xib" file
After moving, MainWindow.xib should only contain: File's Owner, First Responder, App Delegate, Window
In TabBarController.xib, File's Owner and First Responder are set to: UIApplication and UIResponder, respectively.
Change "didFinishLaunchingWithOptions" in the main application delegate to the following:
REMOVE:
[self.window addSubview:tabBarController.view];
ADD:
UITabBarController *uiTab = [[UITabBarController alloc] initWithNibName:#"TabBarController" bundle:nil];
[self.window addSubview:uiTab.view];
With these changes, the application builds and runs, but when the TabBarController loads the tab bar is "empty" -- there don't appear to be any contents in the controller.
In looking in the debugger, either the "init" isn't initializing from the data correctly, or something in the .xib file is not set correctly.
What is the correct solution to this? I realize there are other ways of doing this, and yes, I have them working in other applications.
What I'm looking for however, is a specific solution using the default project, that can be used as a general pattern for setting up iOS code.
Thanks in advance for any help
js
I think i know what you are looking for because i want the same thing.
Create New Empty xib file at interface builder.
Add to the xib TabBarController from the library.
Edit whatever you need on this tab bar controller on the xib.
Of course, save...
Determine from which view controller do want to create that xib with tab bar controller. In other words, who is the view controller that will cause this tab bar controller to appear.
Let's call that view controller ParentViewController
In that view controller, create an IBOutlet to a TabBarController.
Back to the xib, make the identity of the File's Owner to the ParentViewController and of course dont forget to hook up the outlet of the tab bar controller in the file's owner to the tab bar controller in the xib.
save the xib and you are ready to go.
When you want to present that tab bar, just decide which way you want to do it: Modally,Popup or something else (Not inside a navigation controller because Apple dont allow tab bar controllers to be inside navigation controllers).
When you decide, just present your tab bar controller outlet the way to present any other view controller. for example:
[self presentModalViewController:self.myTabBarController animated:YES];
Assuming you start with the "Tab Bar Application" template and move the UITabBarController and associated view controllers to a new nib as you described...
In your new nib, File's Owner should be set to your AppDelegate class. Then connect the outlet "tabBarController" of File's Owner to the UITabBarController.
Then in your -[application:didFinishLaunchingWithOptions:], do not remove this line:
[self.window addSubview:tabBarController.view];
Instead, load the new nib right before that with your app delegate as the owner:
[[NSBundle mainBundle] loadNibNamed:#"TabBarController" owner:self options:nil];
That will set your tabBarController property (since you made that connection in the nib) and then you can proceed as normal. What you were doing was actually creating a whole new UITabBarController, and not loading the one from the nib at all. (well, ok you were loading it for a brief moment, but then not doing anything useful with it)
Hope that helps.

Resources