Как мне получить размеры NSView во время инициализации?

#objective-c #macos #cocoa #graphics

#цель-c #macos #какао #графика

Вопрос:

У меня есть пользовательский вид ( NSView подкласс), и я хотел бы сохранить некоторые данные на основе размеров (ширина / высота) представления при создании экземпляра представления, т. Е. До drawRect вызова.

Я ожидал бы, что смогу использовать initWithFrame и брать границы из переданного NSRect , но если я проверю данные в отладчике, я просто получу NSRect экземпляр с. (x=0, y=0), (width=0, height=0) Предположительно, он еще не инициализирован?

Более загадочным является то, что если я регистрирую ширину фрейма на консоли, я получаю значение дважды:

 - (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        CGFloat width = frame.size.width;
        NSLog(@"width: %f", width);
    }
}
 

Этот код регистрирует:

 21/10/2011 09:40:55.733 Test App: width: 480.000000
21/10/2011 09:40:55.818 Test App: width: 0.000000
 

Это как если бы initWithFrame выполняется в двух отдельных потоках, и у нас есть какое-то условие гонки. Каков правильный способ получить ширину кадра при инициализации представления?

ОБНОВЛЕНИЕ [РЕШЕНО]: теперь эта проблема решена. Оказывается, у меня было два экземпляра моего NSView подкласса в Interface Builder. Один был нарисован в Custom View виде буквы «а», а другой — Object в виде буквы «а» на боковой панели. Я не понимал, что добавление объекта на боковую панель приводит к его созданию во время выполнения. Удалил объект, и теперь мой код работает.

Комментарии:

1. Если бы я пытался это отладить, я бы посмотрел, вызывал ли я initWithFram сам и автоматически получал его с помощью отношения InterfaceBuilder?

2. Он вызывается автоматически, поскольку у меня есть a Custom View в IB, а его Class поле установлено для моего TestCanvas класса (какие подклассы NSView ). Я не создаю экземпляр «вручную» TestCanvas нигде в своем коде. Возможно ли, что он вызывается один раз при NSWindow создании и снова при создании Custom View внутри него или наоборот?

3. Возможно, но время, которое вы регистрируете, предполагает, что он вызывается с размером 0 после правильного размера. Просто поставьте условие, проверяя, равен ли размер 0. Если это не так, обрабатывайте данные по своему усмотрению?

4. Интересно, что они не всегда происходят в таком порядке. Иногда я получаю 0, а затем 480, что придает вес моей теории условий гонки. Предложенное вами условие заставит меня работать (спасибо!), Но это хак, и я бы в конечном итоге хотел понять, что происходит. Я мог бы попробовать создать минимальный рабочий пример с нуля и посмотреть, смогу ли я воспроизвести проблему.

5. Я нашел причину проблемы, см. Обновление выше.

Ответ №1:

Кадр, переданный в initWithFrame, является кадром, используемым представлением, вы уверены, что не создаете два представления или не вызываете это дважды?

Комментарии:

1. У меня есть NSWindow внутри .xib, и внутри него есть Custom View Class поле, для которого установлено значение TestCanvas . Внутри TestCanvas подклассы NSView и обеспечивает реализацию initWithFrame . Все работает так, как ожидалось (я могу рисовать в представлении с drawRect помощью , за исключением того, что initWithFrame вызывается дважды. Вполне возможно, что я получаю два экземпляра TestCanvas, но я не могу сказать почему.