In order to break another problem down into smaller parts, I am trying to set up all the TextKit components. However, I am getting an crash after changing how I initialize NSTextStorage
. For testing purposes I have simplified the project to the following:
import UIKit
class ViewController3: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var myTextView: MyTextView!
override func viewDidLoad() {
super.viewDidLoad()
let container = NSTextContainer(size: myTextView.bounds.size)
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage(string: "This is a test")
layoutManager.addTextContainer(container)
//layoutManager.textStorage = textView.textStorage // This works
layoutManager.textStorage = textStorage // This doesn't work
myTextView.layoutManager = layoutManager
}
}
class MyTextView: UIView {
var layoutManager: NSLayoutManager?
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext();
// Enumerate all the line fragments in the text
layoutManager?.enumerateLineFragmentsForGlyphRange(NSMakeRange(0, layoutManager!.numberOfGlyphs), usingBlock: {
(lineRect: CGRect, usedRect: CGRect, textContainer: NSTextContainer!, glyphRange: NSRange, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
// Draw the line fragment
self.layoutManager?.drawGlyphsForGlyphRange(glyphRange, atPoint: CGPointMake(0, 0))
})
}
}
It crashes at enumerateLineFragmentsForGlyphRange
with an exception code of EXC_I386_GPFLT. That code isn't very explanitory. The basic problem seems to be coming down to how I am initializing NSTextStorage
.
If I replace
let textStorage = NSTextStorage(string: "This is a test")
layoutManager.textStorage = textStorage
with this
layoutManager.textStorage = textView.textStorage
then it works. What am I doing wrong?
It seems the way to do things, is to add the NSLayoutManager to the NSTextStorage object, (using addLayoutManager:) rather than setting the textStorage property on the layout manager.
From Apple's documents:
This method is invoked automatically when you add an NSLayoutManager to an NSTextStorage object; you should never need to invoke it directly, but you might want to override it. If you want to replace the NSTextStorage object for an established group of text-system objects containing the receiver, use replaceTextStorage:.
Link to setTextStorage: for NSLayoutManager
Presumably something gets done in 'addLayoutManager:' which doesn't get done in setTextStorage, causing the crash.
You might also want to increase the scope of the textStorage variable, if it appears that it's getting cleared up once viewDidLoad finish.
来源:https://stackoverflow.com/questions/30796174/how-to-initialize-nstextstorage-with-a-string-in-swift