Interface-Builder: "combine" NSView-class with .xib

interface-builder, macos

Solution

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

Problem

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?

Original source