Как настроить NSTextView программно с явным NSLayoutManager, NSTextStorage, NSTextContainer?

Следуя документации Apple, я пытаюсь настроить простой NSTextView через два метода конструктора.

Я размещаю приведенный ниже код внутри viewDidAppear метод контроллера представления представления контента. textView является экземпляром NSTextView, frameRect - это рамка представления содержимого.

Следующий код Swift работает (дает мне редактируемый textView с текстом, отображаемым на экране):

    textView = NSTextView(frame: frameRect!)
    self.view.addSubview(textView)
    textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello"))

Следующее НЕ работает (текстовое представление не редактируется и текст не отображается на экране):

    var textStorage = NSTextStorage()
    var layoutManager = NSLayoutManager()
    textStorage.addLayoutManager(layoutManager)
    var textContainer = NSTextContainer(containerSize: frameRect!.size)
    layoutManager.addTextContainer(textContainer)
    textView = NSTextView(frame: frameRect!, textContainer: textContainer)

    textView.editable = true
    textView.selectable = true
    self.view.addSubview(textView)

    textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))

Что я делаю не так во втором примере? Я пытаюсь следовать примеру, приведенному в "Руководстве по архитектуре текста Какао" от Apple, где обсуждается настройка NSTextView явно создавая свою сеть вспомогательных объектов.

3 ответа

Решение

Вы должны сохранить ссылку на NSTextStorage переменная, которую вы создаете. Я не совсем уверен в механике всего этого, но похоже, что текстовое представление содержит только слабую ссылку на свой объект хранения текста. Как только этот объект выходит из области видимости, он больше не доступен для просмотра текста. Я думаю, что это соответствует шаблону проектирования MVC, где представления (NSTextView в этом случае) должны быть независимыми от своих моделей (NSTextStorage объект).

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    var textView: NSTextView!
    var textStorage: NSTextStorage! // STORE A REFERENCE

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        var view = window.contentView as NSView
        textStorage = NSTextStorage()
        var layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        var textContainer = NSTextContainer(containerSize: view.bounds.size)
        layoutManager.addTextContainer(textContainer)
        textView = NSTextView(frame: view.bounds, textContainer: textContainer)

        textView.editable = true
        textView.selectable = true
        view.addSubview(textView)

        textView.textStorage?.appendAttributedString(NSAttributedString(string: "Hello more complex"))
    }
}

Протестировано в Xcode 12.4. на детских площадках:

      import Cocoa
import AppKit

let textViewFrame = CGRect(x: 0, y: 0, width: 250, height: 90)
let textStorage = NSTextStorage()
var layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
var textContainer = NSTextContainer(containerSize: textViewFrame.size)
layoutManager.addTextContainer(textContainer)
let textView = NSTextView(frame: textViewFrame, textContainer: textContainer)
textView.isEditable = true
textView.isSelectable = true
textView.textColor = NSColor.red
textView.string = "Why is this so complicated..."
#import <Cocoa/Cocoa.h>

@interface TextViewController : NSObject {

    NSLayoutManager *secondLayout;

    IBOutlet NSSplitView *columnView;
    IBOutlet NSTextView *bottomView;

}

- (IBAction) addColumn: (id)sender;

@end
#import "TextViewController.h"

@implementation TextViewController

- (void)awakeFromNib
{
    NSTextStorage *storage = [bottomView textStorage];
    secondLayout = [NSLayoutManager new];
    [storage addLayoutManager: secondLayout];
    [secondLayout release];
    [self addColumn: nil];
    [self addColumn: nil];
}


- (IBAction) addColumn: (id)sender
{
    NSRect frame = [columnView frame];

    NSTextContainer *container = [[NSTextContainer alloc]
                                  initWithContainerSize: frame.size];
    [container setHeightTracksTextView: YES];
    [container setWidthTracksTextView: YES];

    [secondLayout addTextContainer: container];
    [container release];
    NSTextView *newView = [[NSTextView alloc] initWithFrame: frame
                                              textContainer: container];
    [columnView addSubview: newView];
    [newView release];
}

@end
Другие вопросы по тегам