Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

enter image description here

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?

like image 522
swalkner Avatar asked Aug 21 '13 09:08

swalkner


1 Answers

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

like image 95
foundry Avatar answered Nov 16 '22 02:11

foundry