Я родом из C / C ++ и сейчас немного изучаю Cocoa и Objective-C.
У меня странное поведение, связанное с ленивой инициализацией (если я не ошибаюсь), и я чувствую, что я 'Мне не хватает чего-то очень простого.
Настройка:
- Xcode 10.1 (10B61)
- macOS High Sierra 10.13.6
- началось с нуляКакао-проект
- использует раскадровку
- добавить файлы TestMainView.m / .h
- под контроллером представления в main.storyboard, установите пользовательский класс
NSView
как TestMainView
- протестировано в сборках отладки и выпуска
По сути, я создаю NSTextView
внутри контроллера представления, чтобы иметь возможность писать некоторый текст.В TestMainView.m я создаю цепочку объектов программно, как описано здесь
Существует два пути:
- Первый из них включается установкой
USE_FUNCTION_CALL
в 0, весь код запускается внутри awakeFromNib()
. - . Второй путь включается путем установки
USE_FUNCTION_CALL
в 1. Это делает текстовый контейнер и текстовое представление выделенными из вызова функции addNewPage ()и возвращает контейнер текста для дальнейшего использования.
Первый путь к коду работает так же, как и ожидалось: я могу написать некоторый текст.
Однако второй путь к коду просто не работает, потому что при возврате, textContainer.textView
- это ноль (textContainer
само значение вполне в порядке).
Что еще более тревожно (и именно здесь я подозреваю, что виноват ленивый init), так это если я "принудительно" textContainer.textView
значение в то время как внутри вызова функции, то все работает просто отлично.Вы можете попробовать это, установив FORCE_VALUE_LOAD
в 1.
Это не обязательно должен быть if()
, он также работает с NSLog()
.Это даже работает, если вы устанавливаете точку останова в строке возврата и используете отладчик для печати значения ("p textContainer.textView")
Так что мои вопросы:
- этосвязано с ленивой инициализацией?
- это ошибка?Есть ли обходной путь?
- я думаю о программировании Какао / ObjC неправильно?
Я действительно надеюсь, что что-то здесь упущено, потому что я не могу ожидать случайной проверки переменных здесьи там в классах Какао, надеясь, что они не повернутся nil
.Он даже не работает тихо (без сообщения об ошибке, ничего).
TestMainView.m
#import "TestMainView.h"
#define USE_FUNCTION_CALL 1
#define FORCE_VALUE_LOAD 0
@implementation TestMainView
NSTextStorage* m_mainStorage;
- (void)awakeFromNib
{
[super awakeFromNib];
m_mainStorage = [NSTextStorage new];
NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
#if USE_FUNCTION_CALL == 1
NSTextContainer* textContainer = [self addNewPage:self.bounds];
#else
NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:NSMakeSize(FLT_MAX, FLT_MAX)];
NSTextView* textView = [[NSTextView alloc] initWithFrame:self.bounds textContainer:textContainer];
#endif
[layoutManager addTextContainer:textContainer];
[m_mainStorage addLayoutManager:layoutManager];
// textContainer.textView is nil unless forced inside function call
[self addSubview:textContainer.textView];
}
#if USE_FUNCTION_CALL == 1
- (NSTextContainer*)addNewPage:(NSRect)containerFrame
{
NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:NSMakeSize(FLT_MAX, FLT_MAX)];
NSTextView* textView = [[NSTextView alloc] initWithFrame:containerFrame textContainer:textContainer];
[textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
#if FORCE_VALUE_LOAD == 1
// Lazy init ? textContainer.textView is nil unless we force it
if (textContainer.textView)
{
}
#endif
return textContainer;
}
#endif
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
@end
TestMainView.h
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface TestMainView : NSView
@end
NS_ASSUME_NONNULL_END