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

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

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;
}

Control-drag to AppDelegate only

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.

How do I have two buttons go to the same IBOutlet in Xcode 5?

Is there a simple way in doing this? Like dragging the button to the target?
An IBOutlet is just a way to automate instantiating a variable with an object. A pointer to a UIButton cannot simultaneously reference two objects. So, no you cannot hook up two buttons to the same IBOutlet.
Since you mention "target" in your question, perhaps what you want to know is how to have two buttons invoke the same method (IBAction). There are a couple of ways to do this. In the simplest case:
right-click on the button,
drag from the appropriate sent event (probably touch-up-inside) to the file owner
as you hover over the file owner, you'll see a pop-up with all the methods marked as IBActions; select the method you wish to invoke.

Create a custom view using a nib and use it in a window

I have been struggling quite a bit with this problem and I can't seem to figure it out by myself.
This is the situation:
I want to have a custom Nib-based view, with its own ViewController. I then want to add this view to a window. Therefore the window should contain my custom view.
So I go about and create a very simple example like this:
In Xcode 4 I create a new blank document-based Cocoa application
I create a new Cocoa Class which should extend from NSViewController (which causes the nib to be created along with the .h and .m file. The name of the created .h, .m und .xib file is FaceViewController for testing purposes it should only display text for now.
I open the NSViewController.xib in InterfaceBuilder and add a multi-line text component and place it in the custom view, which is already in the xib file. I make the text span the whole view.
In MyDocument.xib I also add a Custom View place holder, which should be replaced with my custom FaceView.
From this starting point on, everything I tried to include the created View + ViewController on my MyDocument.xib failed and the area where my text should be shown remains empty (just like the background of the underlying window.
So my question really is what I need to do, so that my FaceView gets loaded into the Custom View which I placed on MyDocument.xib. Here are some things which are unclear to me:
The custom View extends from NSView so I wanted to change this to my FaceView but the view does not exist as a class but is defined in InterfaceBuilder in the xib, do I need to set this to anything other than NSView?
Do I have to alloc, init the FaceViewController in code or is it enough to drag it into either of my two .xibs?
Can I use InterfaceBuilder to place my FaceView or do I have to do this programmatically?
I really thought that creating a custom view like this would be a piece of cake but it turned out quite the opposite so far, so any help would be greatly appreciated.
You can create your FaceViewController either by adding one to the MyDocument.xib or by creating it with alloc, init.
To place your FaceView you'll have to do it programmatically, you can use
[customView addSubview:[FaceViewController view]];
of if you want to replace the view
[customView replaceSubview:oldView with:[FaceViewController view]];

Cannot bind NSSlider in IB?

I just created a new Xcode project. In the AppControl class Header file I have the following objects defined (and some other ones, too):
IBOutlet NSImageView *inputImageView;
IBOutlet NSImageView *outputImageView;
IBOutlet NSTextField *myNoiseLevel;
IBOutlet CGFloat *mySharpness;
After putting the basic code into the .h and .m files, I then went into Interface Builder and created my UI. I was able to bind the two NSImageView controls in IB to the corresponding NSImageView objects listed above. And I was able to bind a couple of other objects/controls, also. But I am NOT able to bind the last two items listed (myNoiseLevel and mySharpness) to the NSSlider controls I have on the application main window. I'm not sure why. I know this kind of thing is probably hard to diagnose, because it is not "strictly code related," but if there is something "tricky" about binding sliders please let me know what the main "suspects" are that I should check.
This is my first attempt to use a slider control through IB. I have a book (Cocoa programming for Mac OS X, 3rd ed., by A. Hillegass) that I am using to learn about the basic way to do this stuff. And he has a slider example in there. But his slider example is "continuous" and it uses key path binding. I think this is overkill for what I want/need to do -- I just want to pull the value from the slider when another button is pushed (no need for "continuous" update). So I am trying to directly bind the "outlets" listed when I right-click on my App Control object (one for each of those items shown above), to the slider controls on my window. But when I cntl-drag from the AppControl outlet up to the corresponding slider, the slider will not "accept" the arrow I'm dragging.
Does this make sense? Any idea what I'm doing wrong and/or what I need to do to make the binding work? I have tried saving / building / closing & reopening IB and Xcode -- all to make sure IB has the latest version of everything. Still no luck, though.
One last thing ... What I really need are CGFloat numbers, from the slider. Can I simply declare the Outlet as CGFloat type ... or do I need to define it as NSTextField (or something else), and then convert it to Float in my program? You can see in the IBOutlets I pasted above, that I was trying different data types for the outlets (trying to see if my defining them as CGFloat was somehow preventing the bindings).
Make the outlet an NSSlider*. You should then be able to connect to it. When you need the value (eg, in response to the button press you mention) call [yourSliderOutletName doubleValue].
More generally: an IBOutlet is an ivar that can be filled in with a pointer to the actual object awoken from a NIB file. As such, it needs to be of an appropriate type to hold that pointer -- the object's actual class, or one of its superclasses or protocols, or (least informatively) id. You can't just arbitrarily connect an object to any old variable, like your CGFloat. There's no implicit conversion -- how is the system supposed to know what you want?

Resources