Skip to content

Instantly share code, notes, and snippets.

@soffes
Last active July 1, 2023 10:14
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soffes/23e67046a749258454578ff886614e29 to your computer and use it in GitHub Desktop.
Save soffes/23e67046a749258454578ff886614e29 to your computer and use it in GitHub Desktop.
Fast, concrete text storage intended to be subclassed.
import UIKit
/// Fast, concrete text storage intended to be subclassed.
class BaseTextStorage: NSTextStorage {
// MARK: - Properties
private let storage = NSMutableAttributedString()
// MARK: - NSTextStorage
override var string: String {
return storage.string
}
override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key: Any] {
assert(location < length,
"Tried to access attributes at out of bounds index \(location). Length: \(length)")
return storage.attributes(at: location, effectiveRange: range)
}
override func replaceCharacters(in range: NSRange, with string: String) {
assert(NSMaxRange(range) <= length,
"Tried to replace characters at out of bounds range \(range). Length: \(length)")
let stringLength = (string as NSString).length
if range.length == 0 && stringLength == 0 {
return
}
beginEditing()
storage.replaceCharacters(in: range, with: string)
edited(.editedCharacters, range: range, changeInLength: stringLength - range.length)
endEditing()
}
override func setAttributes(_ attributes: [NSAttributedString.Key: Any]?, range: NSRange) {
assert(NSMaxRange(range) <= self.length,
"Tried to set attributes at out of bounds range \(range). Length: \(length)")
beginEditing()
storage.setAttributes(attributes, range: range)
edited(.editedAttributes, range: range, changeInLength: 0)
endEditing()
}
}
@dasmer
Copy link

dasmer commented Sep 2, 2016

Why import UIKit / AppKit here?

@soffes
Copy link
Author

soffes commented Jan 9, 2017

@dasmer so it works on both :)

@DivineDominion
Copy link

Keep in mind that replacing the NSMutableAttributedString with a NSTextStorage instance as backing storage speeds up things tremendously.

@soffes
Copy link
Author

soffes commented Sep 14, 2018

@DivineDominion you can't initialize one directly per the documentation. That's why this class exists.

@krzyzanowskim
Copy link

How did you measure speed up here? From what I see, NSMutableAttributedString is significantly slower than NSTextStorage. Especially when using with Swift (See https://bugs.swift.org/browse/SR-6197)

@soffes
Copy link
Author

soffes commented May 26, 2020

@krzyzanowskim interesting. I talked with the Swift folks about this years ago and my understanding was this was fixed. If that's not the case, use the Objective-C version instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment