Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set up an NSTextView programmatically with explicit NSLayoutManager, NSTextStorage, NSTextContainer?

Following the apple documentation I am trying to set up a simple NSTextView via its two constructor methods.

I am placing the below code inside the viewDidAppear method of the view controller of the content view. textView is an instance of NSTextView, frameRect is the frame of the content view.

The following Swift code works (gives me an editable textView with the text showing on the screen):

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

The following does NOT work (text view is not editable and no text shown on the screen):

    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"))

What am I doing wrong in the second example? I am trying to follow the example given in Apple's "Cocoa Text Architecture Guide" where they discuss setting up an NSTextView by explicitly instantiating its web of helper objects.

like image 687
Sam Avatar asked Mar 13 '15 14:03

Sam


2 Answers

You need to keep a reference to the NSTextStorage variable you create. I'm not quite sure about the mechanics of it all, but it looks like the text view only keeps a weak reference to its text storage object. Once this object goes out of scope, it's no longer available to the text view. I guess this is in keeping with the MVC design pattern, where views (the NSTextView in this case) are meant to be independent of their models (the NSTextStorage object).

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"))
    }
}
like image 77
Paul Patterson Avatar answered Oct 20 '22 13:10

Paul Patterson


Tested under Xcode 12.4. in Playgrounds:

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..."
like image 36
Darkwonder Avatar answered Oct 20 '22 13:10

Darkwonder