I am learning Stanford CS193p course with Xcode 4.3.3. I think the screenshot below is pretty much self-explaining. But i will describe the problem with words anyway.
I control-drag a UILabel from storyboard to corresponding implementation file to make the IBOutlet #property. Then I see two connections displayed when clicking the filled circle in the left side of the editor where shows line numbers. I don't know how to delete it.
Moreover, I see only ONE connection in storyboard's connections inspector of the UIlabel.
More weird, when I try to set the UILabel's text inside the setter of a public preperty, it fails to update the label's text:
-(void) setQuestion:(NSString *)question
{
_question = question;
self.questionLabel.text = question;
NSLog(#"The quesion is %#",question);
NSLog(#"The quesion label text is %#",self.questionLabel.text);
}
I use two NSLog to debug and get the following. It shows the NSString *question is #"What do you want your label to say?", yet the self.questionLabel.text is null. The value assign fails. I suspect this relate to the duplicated connections thing mentioned above.
2012-07-29 04:03:53.817 Kitchen Sink[18628:f803] The quesion is What
do you want your label to say?
2012-07-29 04:03:53.820 Kitchen
Sink[18628:f803] The quesion label text is (null)
The following is the screenshot showing the duplicated connections. I am probably missing something obvious, please help.
I would stalk this up to Xcode storyboard wonkiness.
First, try a clean of the project and a re-build.
Should you still have that problem, manually define the #property without dragging from the AskerViewController view to the AskerViewController implementation (.m) file by doing the following.
Cut that IBOutlet #property line in the interface section of the implementation (.m) file for AskerViewController. Click the label in storyboard. Disconnect any binding that label to the AskerViewController. Clean the project. Then, paste back in the property, and control-drag from the label to the view controller orb at the bottom of the AskerViewController view in your storyboard file.
Related
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;
}
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
Once the code bellow is executed, the textfield's text doesn't change in the UI to "Fly" but the second NSLog does print "TextField: Fly" as it should.
#property (strong, nonatomic) IBOutlet UITextField *typeTextField;
....
UITableViewCell* cell = [self.theTableView dequeueReusableCellWithIdentifier:#"TypeCell"];
self.typeTextField = (UITextField*)[cell viewWithTag:1];
NSLog(#"TextField: %# ", self.typeTextField.text);
self.typeTextField.text = #"Fly";
NSLog(#"TextField: %# ", self.typeTextField.text);
Any help would be much appreciated.
You almost definitely forgot to connect the outlet for the UITextField in interface builder. Bring up the .xib file that that typeTextField is visible in, click on typeTextField, then show the Utility pane (the one on the far right in Xcode 4+). Click the Connections Inspector (the one that looks like a right arrow) and drag a New Referencing Outlet to your File's Owner.
When you don't connect the UITextField you drew in Interface Builder with the IBOutlet that you identified in your source file, both UITextFields get created as separate entities. You can make changes and work with the valid typeTextField with a broken IBOutlet, but it'll never appear on your view.
Consult How to connect an IBOutlet from an UITableViewController directly to custom cell? and http://www.youtube.com/watch?v=d_kO-J3DYvc on properly wiring your custom UITableViewCell objects.
I'm still struggling with the View-Based NSOutlineViews introduced with OSX Lion. While everything works quite good now, I'd like to add Mail.app-like unread badges to rows.
Is there a better way for View-Based NSOutlineViews than following the example of -(void)drawBadgeForRow:(NSInteger)rowIndex inRect:(NSRect)badgeFrame in PXSourcelist ?
Thanks, Bucks
In case anybody encounters the same problem, I've found a solution in the Lion release notes that is actually quite simple.
First subclass NSTableCellView, add an IBOutlet for an NSButton and a #synthesize/#property statement to it. Then open the NSTableCellView that should have a badge in Interface Builder. Set it's class to your newly created subclass and add a button to it. Set the button style to "inline" and it's type to "switch".
Now select the NSTableCellView again and connect the NSButton IBOutlet to your added button.
That's it. You can now call e.g. [[cellView button] setTitle#"123"]] to set the rows badge label to 123 or any arbitrary string.
I've got a cocoa application that reads in a text file. I'd like to display that text in a multi-line label, but I for the life of me can't figure it out. I opened up my .nib file and poped a multi-line label down but after that I'm stuck.
I don't have any experience working with Xcode or Cocoa, mostly Eclipse, Visual Studio, and pretty much every other IDE except Xcode which seems very foreign.
If you have the text in an NSString, you can easily put it in the label.
First, in the .h file (or header) of your controller class, create a new IBOutlet so you can refer to the label:
IBOutlet NSTextField *myLabel;
Go into the .xib file where the label is. Control-drag from the controller object to the label, and select the "myLabel" option to apply it to that specific label.
Then, in the method where you want to put the text in the label, type the following:
[myLabel setStringValue:myString]; (where "myString" is your NSString)
Note: This is all assuming you know how to do basic things like controller classes- if not, I'd definitely check out Cocoa Dev Central (http://www.cocoadevcentral.com/.)