I have created an extremely simple test program. It has one button. Clicking the button brings up an NSPopover with a label. That label is on a separate xib file with its own NSViewController.
The Goal is to, when on the main screen, when I click the button, a popover will show the xib file of the viewcontroller. And the label of the xib file should have it's text set to "It works".
Well.. It works, but only on after the second loading of the popover. On the first click of the button, the label still has its old default value. But from the 2nd click and onwards, "It works". Does any one have an idea what can be causing this issue? Its only about 5 lines of code The code can be seen on this repository --> https://github.com/patchthecode/testtest
Call [mainScreenPopoverViewController view]; in - (void)windowDidLoad method. This will load your view into memory.
Before call [mainScreenPopoverViewController view]; (textfield address is 0x0)
You should not use strong property for all IBOutlet.
#property (nonatomic, strong) IBOutlet NSTextField *textField;
Take a look at Resource Programming Guide
From a practical perspective, in iOS and OS X outlets should be
defined as declared properties. Outlets should generally be weak,
except for those from File’s Owner to top-level objects in a nib file
(or, in iOS, a storyboard scene) which should be strong. Outlets that
you create should therefore typically be weak, because:
Outlets that you create to subviews of a view controller’s view or a
window controller’s window, for example, are arbitrary references
between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example,
UIViewController’s view outlet, or NSWindowController’s window
outlet).
Related
I would like to link an imageView and a textField in my xib grafical user interface to the belonging Outlets from the NSCollectionViewItem (which is an element from the application kit). But while linking the bindings following message pops up:
"Xcode cannont find a Key Value Coding compliant property named #property (assign) IBOutlet NSImageView *imageView NS_AVAILABLE_MAC(10_7); in the class NSCollectionViewItem."
So, for me it is not possible to connect these objects. Therefore I don't get any Referencing Outlets for the Text Field or the Image View.
In an another xib the same bindings exist already. But they are marked with a white exclamation point and also show up a strange message: "NSCollectionViewItem does not have an outlet named imageView."
Does anyone knows how to solve the problem? Would be great.
I just tested this and can confirm, regardless of the NIB's deployment target. It seems like an Xcode bug.
I created a custom subclass of NSCollectionViewItem with no actual customizations. I set the class of the collection view item in the NIB to my custom subclass and the outlets were suddenly available. I then set the class back and they were still available. I connected one and built and got no warnings or errors.
I created a custom view. It has a delegate that it will notify when some of its buttons are pressed.
I added this to the view controller's viewDidLoad:
self.myCustomView.delegate=self;
So far everything works fine.
But that's not cool enough. I want to do it the table view style where I can just right drag from the view to the File's Owner and (ta-da!) it's automatically set.
Add the IBOutlet keyword to the delegate property of your class:
#property (nonatomic, assign) IBOutlet id<MyViewDelegate> delegate;
The IBOutlet keyword tells the nib editor to let you make a connection to that property.
You could also say this:
#property (nonatomic, assign) IBOutlet MyView *delegate;
And then IB will only allow you to connect it to a MyView. But a protocol or id is more flexible.
EDIT: One point has been lost due to focus on IB
You said:
I created a custom view. It has a delegate that it will notify when some of its buttons are pressed.
Receiving button events is the role of a view controller, sometimes however a delegate will be used for finer grained control of certain events.
In general dont create a delegate for button presses on a view that is a primary window in which case you should be handling your button events in a ViewController. Buttons sit on a parent view that will forward events up the responder chain (you still need to connect them to a target). Im not saying you shouldn't ever use the delegate pattern for button presses but, buttons have their own connections to view controllers in IB with drag and drop as you wish. But there are situations like yours which are perfectly valid.
This is an OS X application. I am designing a custom sheet. Within my XIB file I have the sheet's window and a subclass of NSViewController which is responsible for controlling the views within the window/sheet. The owner of the XIB is another controller class.
I placed an NSTextField into the window's content view. In my NSViewController I created an IBOutlet declaration for the NSTextField and ensured the outlet was properly connected in the XIB.
I overrode -[NSViewController setRepresentedObject:] and within that method I am looking at the representedObject and depending on it's properties I am either removing the NSTextField from it's superview or I'm adding it back into the superview.
The first time I display my sheet with a representedObject that dictates the textfield should be removed from the superview. This works just fine.
The second time I display my sheet with a representedObject that dictates the textfield should be added back to the superview my application crashes with EXC_BAD_ACCESS when calling -[NSView addSubview:].
Running Instruments shows that the NSTextField was a Zombie at the time I tried to add it back to the superview. Instruments also indicates that every call to retain/release/autorelease was performed by either AppKit or Foundation - so at no point does any of my code increase or decrease the retain count. In fact the only two lines that reference the IBOutlet in my code are a call to -[NSView removeFromSuperview] and -[NSView addSubview:].
Am I doing something wrong or is this a bug in OS X? An IBOutlet should never be deallocated unless the XIB is unloaded.
Well naturally I figured it out like 2 minutes after I posted my question.
There are actually 2 textfields in my XIB both of which have identical behavior as described in the question. Only one of the textfields was turning into a NSZombie which made things more confusing.
Well when I was designing the XIB I laid down one NSTextField, configured it, and then copied it by holding Option while dragging the NSTextField. I did ensure the outlets were setup properly for the copied NSTextField, but for some reason the objects remained the same.
The solution was to delete the offending NSTextField and then drop a fresh one from the palette and configure it that way.
I so far only have the interface builder layout
I'm not clear on the syntax to reference all of these items from the layout
I know that IBOutlet has to be used somewhere, but I need a bit more handholding on what this objective C is doing. Nothing I've read tells me exactly why some declarations start with + and others with -
What I want to do is click a button in my layout, have a modal view pop up and change the background on the entire layout.
so the first step is referencing all these items I've made in the nib. help? (or post a link to more intuitive tutorials that you know about)
So you probably want to create an IBOutlet for your background view. Maybe it's a UIImageView that you can set it's image property based on what the user selects in the modal view. For this you would just declare the UIImageView you have in your IB file
UIImageView *imageView;
and then declare it as a property
#property (nonatomic,retain)IBOutlet UIImageView *imageView;
and synthesize it in your .m file
#synthesize imageView;
Don't forget to release it if you're not using ARC.
Then you can open up interface builder and if you click on your view controller File's Owner and go to the connections inspector you will see there is a new connection there for imageView. Just drag that connection over to your UIImageView in the IB file and that's it. You now have a reference in your code that connects to your UIImageView in IB.
That will allow you to set the UIImageView in your code by typing something like
self.imageView.image = [UIImage imageNamed:theNameTheUserJustPicked];
In order to get the modal view, you need an IBAction to trigger a method in your code so declare one like this in your .h file of your main nib.
- (IBAction)displayViewBackgroundChooser;
and then define it in your .m file.
- (IBAction)displayViewBackgroundChooser {
//present your new view on screen here
}
Then go back to interface builder and click on the File's Owner again. You should see it there in the connections inspector and then you can connect it to a button, for example, that would trigger that method.
Hope this helps to clear things up a bit on IBOutlets and IBActions.
You can make your UI elements created in IB interact with your code by means of IBOutlets and IBActions.
In your case, I would associate an action to the button, so that it is fired when the button is clicked; the action would open a modal view, and you could change the background of that view in the viewDidLoad method of the associated controller.
Here you find a video tutorial about adding an outlet. And here, the same about actions.
About your doubt on + and -, - identifies a normal method defined in a class; + defines a class method, i.e., a method that you can call on the class directly, without having to instantiate it first. Have a look at this S.O. article for more.
I am implementing a preferences window, with a subclass of NSToolbarItem that has an IBOutlet to an NSView (the idea being that when an item is clicked, it will display its view). However, when I connect a toolbar item to an instance of the subclass, that item's image disappears and it is not clickable (although the text remains dark and does not fade).
If I disconnect the IBOutlet, everything works again (well, nothing does, since it isn't bound to the view, but you get the idea).
Connecting the view to the NSToolbarItem actually sets the view where the toolbar item's image normally is. This is useful in cases where you need a view in the toolbar (for example, the iTunes volume slider), but not in your case.
What you need to do is create an NSViewController for your view, and create an IBAction that shows the view. You should be able to connect the IBAction to the toolbar item (in Interface Builder), and everything should work as expected.