Пользовательский вид, созданный с помощью Interface Builder, не отображается при вызове в других представлениях

У меня есть xib для главного окна, и я создал пользовательский вид в следующих шагах:

  • Создайте новый класс, который наследует от NSView.

MyView.h:

    #import <Cocoa/Cocoa.h>
    IB_DESIGNABLE
    @interface MyView : NSTableCellView
    @end

MyView.m:

    #import "MyView.h"

    @implementation MyView

    - (void)awakeFromNib {
        NSLog(@"Post view awaking from nib.");
    }

    @end
  1. Создайте новый xib и задайте класс корневого представления классу, созданному выше. И дизайн в этом xib.
  2. Установить выходы из xib в класс.

И я попытался использовать это настраиваемое представление в главном окне в следующих шагах:

  • Перетащите пользовательский вид в главное окно xib.
  • Задайте класс этого пользовательского представления для класса, созданного выше.

Но ничего не делает. Из журнала я вижу, что код из awakeFromNib из класса пользовательского представления выполнен. Когда я устанавливаю класс IB_DESIGNABLE, представление становится пустым в главном окне xib, отличном от того, что я разработал.

Я попытался установить владелец файла настраиваемого представления xib в пользовательский класс, но ничего не изменилось.

Я предполагаю, что проблема заключается в том, что пользовательский вид xib файла фактически не загружен. Когда я искал его, похоже, немного ссылок на эту точную тему. Итак, как я должен достичь этой цели? I.e., спроектировать представление в IB, реализовать его методы в классе, связать эти два и выставить его точно так же, как системное представление для использования в других xibs?

ОБНОВЛЕНИЕ:

Я нашел учебник и понял, чего мне не хватает (для правильного отображения представления при его создании). Мне нужно добавить выход из представления в xib в класс вида:

@property (nonatomic, strong) IBOutlet NSView *view;

а затем загрузите его в метод (id)initWithCoder:(NSCoder *)coder.

[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];

Но представление не будет отображаться в построителе интерфейса.

Ответ 1

Ваша догадка правильная: xib не загружается. Погрузчик nib не знает о вашем пользовательском представлении nib. Рамка nib не предоставляет возможности для определения этого соединения, поэтому вам нужно написать код для загрузки xib.

Вот что я буду делать. Добавьте свойство contentView к своему пользовательскому представлению:

@interface MyView ()

@property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;

@end

В своем пользовательском представлении nib установите собственный класс корневого представления обратно в NSView и отключите от него все (более длинные) выходные соединения. Задайте пользовательский класс File Owner для вашего пользовательского имени класса (например, MyView). Подключите корневой режим к файловому владельцу contentView и подключите все остальные выходы от File Owner к соответствующим объектам в nib.

Затем реализуйте awakeFromNib в своем подклассе пользовательского вида, чтобы загрузить nib и добавить представление контента в виде подвью:

@implementation MyView {
    BOOL hasLoadedOwnNib: 1;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self loadOwnNibIfNeeded];
}

- (void)loadOwnNibIfNeeded {
    if (hasLoadedOwnNib) {
        return;
    }

    hasLoadedOwnNib = YES;

    [[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
    [self addSubview:self.contentView];
}

@end

Обратите внимание, что вы должны быть осторожны, чтобы не допускать бесконечной рекурсии. Когда ваше приложение загружает главное окно, оно создаст экземпляр MyView и (в конечном итоге) отправит его awakeFromNib. Затем в awakeFromNib, MyView загружает свой собственный nib, где он является файловым владельцем. Погрузчик nib отправляет awakeFromNib в File Owner, и это произойдет, когда вы уже находитесь в -[MyView awakeFromNib]. Если вы не проверите это, вы получите переполнение стека из-за неограниченной рекурсии.

Ответ 2

Вы не предоставляете никакого кода, но вот несколько проверок здравомыслия:

  • Правильно ли задаете имя nib? В iOS его кепки чувствительны, но я не думаю, что это для вас.

  • Проверьте пакет, на самом деле есть ли там? Убедитесь, что это часть цели, которую вы строите.

  • Также может быть проблема с фреймом. Убедитесь, что параметры автоматического изменения размера настроены правильно и все в кадре.

  • Еще одна проверка, которую вы можете сделать, - установить IBOutlets в фактический кадр UIView (или другого), который вас интересует. Затем в awakeFromNib вы можете убедиться, что их фрейм существует или что они существуют вообще.