I'd like to set up a custom NSView in Interface-Builder, but I don't get it to work for OSX.
In my ViewController's .xib, I added a custom view and set the Class to MyCustomView. I created MyCustomView.h, MyCustomView.m and MyCustomView.xib.
In MyCustomView.xib, I set the Class to MyCustomView as well. In MyCustomView.m, - (void)awakeFromNib
is called, but - (id)initWithCoder:(NSCoder *)aDecoder
and - (id) awakeAfterUsingCoder:(NSCoder*)aDecoder
aren't.
What I'd like to achieve is that in my ViewController, the view I added is "filled" with the view I set up in MyCustomView.xib. What's the best way to do that?
EDIT: I don't think I was clear enough...
I've got my ViewController containing a Custom View called MyCustomView.
This view should be of type MyCustomView, where
MyCustomView.h
MyCustomView.m
MyCustomView.xib
exists. I already set the File's Owner of MyCustomView.xib to MyCustomView and I already set the CustomView in my ViewController to MyCustomView - but it doesn't work.
If I do it with
- (void)awakeFromNib {
NSString* nibName = NSStringFromClass([self class]);
NSArray* topLevelObjects;
[[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
topLevelObjects:&topLevelObjects];
NSView* view = topLevelObjects[0];
[view setFrame:[self bounds]];
[self addSubview:view];
}
I only get a view of type NSView, not MyCustomView... Is there no easy way to tell the ViewController.xib that it's a MyCustomView?
EDIT 2: I uploaded a simple project
At https://dl.dropboxusercontent.com/u/119600/Testproject.zip you find a simple project with the MyCustomView (not in a ViewController but in the window.xib) - but it doesn't show the button which is in MyCustomView.xib. I'd like to achieve exactly that - what's the simplest, best way?
EDIT - apologies, my existing answer failed to take into account the need to connect outlets and actions. This way should do it...
Given the files...
MyCustomView.h
MyCustomView.m
MyCustomView.xib
In MyCustomView.h
declare IBOutlets for your interface elements. You need at least one, to hold a pointer to the top-level view in the xib file
@property (nonatomic, strong) IBOutlet NSView *view;
In MyCustomView.xib
- ensure that there is only one top-level view
- set file's owner class to MyCustomView in the Identity Inspector
- ensure that the top-level view is set to the default
NSView
class.
- now you can connect IBOutlets declared in MyCustomView.h to interface objects in the xib file. At very least you need to connect up the top-level view to your
view
outlet.
In MyCustomView.m:
- (id)initWithFrame:(NSRect)frame
{
NSString* nibName = NSStringFromClass([self class]);
self = [super initWithFrame:frame];
if (self) {
if ([[NSBundle mainBundle] loadNibNamed:nibName
owner:self
topLevelObjects:nil]) {
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
[self.myCustomButton setTitle:@"test success"];
}
}
return self;
}
In your window's xib file, add a custom NSView and change it's class to MyCustomView.
in OSX prior to 10.8 the method loadNibNamed
was a class method - use it instead if you need backwards compatibility, but it is deprecated now:
[NSBundle loadNibNamed:@"NibView" owner:self]
Note that MyCustomView.xib's view is NOT MyCustomView's view, but the sole subview of it's view (this is similar to the way a tableViewCell possesses a single contentView).
In the project sample you have posted, you need to make the following changes:
in MyCustomView.h
. add an NSView property
in MyCustomView.xib:
. change the top-level view from MyCustomView
custom class to NSView
(the default)
. set the File's Owner to MyCustomView
.
. connect IBOutlets from File's owner's view
and myCustomButton
to interface view and button
. for testing make the view a lot smaller and push the button up to the top right (you won't see it in your window as it is here)
in MyCustomView.m:
. replace all of your implementation code with the initWithFrame
method here
In order to load a custom subclass of a view or a control (or any other class that can be used in Interface Builder for that matter), you need to add the base version (NSView in your case, and as you have done), then select that object in the window and go to the Identity Inspector (Cmd-Opt 3).
Instead of the pre-defined value for Class (NSView, in your case), type in the name of your custom subclass. Voilà!
A small detail related to the IB UX is that you'll probably have to move the focus from the input field in order for that change to be registered when you build and run the app.