Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSTextStorage with long text inside. Performance

I have a NSTextStorage with long text inside (like 500 pages in a book and more than 9000 on a device for current font). I'm distributing this text for textcontainers this way:

let textStorageLength = defaultTextStorage?.length ?? 0
while layoutManager!.textContainer(forGlyphAt: textStorageLength - 1, 
                                   effectiveRange: nil) == nil {
  let textContainer = NSTextContainer(size: textContainerSize)
  layoutManager!.addTextContainer(textContainer)
  pagesCount += 1
}

The problem is that it takes long period of time to init all this containers etc. I already have made some improvements like changing code from using

while lastRenderedGlyph < layoutManager!.numberOfGlyphs {

and

lastRenderedGlyph = NSMaxRange(layoutManager!.glyphRange(for: textContainer))

cz it is working much more slower.

So, what other improvements can I make? On iPhone 7 it takes like 7 seconds for initing, on iPhone 5s 20 secs +

Time profiler shows, that almost all the time is getting insertTextContainer function (addTextContainer).

Any suggestions?

like image 650
Vlad Pulichev Avatar asked May 16 '26 23:05

Vlad Pulichev


1 Answers

Layout manager invalidates layout on addTextContainer method call and rebuilds layout on textContainer(forGlyphAt:effectiveRange:). You can check it by setting delegate for layout manager and observing layoutManagerDidInvalidateLayout. So rather then do layout once, you are doing it 500 times - once for every added text container.

You can add text containers in batches to reduce number of layouts, e.g.

  var lastTextConainer: NSTextContainer? = nil
  while nil == lastTextConainer {
     for _ in 1...100 {
       let textContainer = NSTextContainer(size: textContainerSize)
       layoutManager.addTextContainer(textContainer)
     }
     lastTextConainer = layoutManager.textContainer(forGlyphAt: layoutManager.numberOfGlyphs - 1, effectiveRange: nil)
  }
  let pagesCount = layoutManager.textContainers.index(of: lastTextConainer!)! + 1

Empty text containers at the end you can leave or remove starting from last text container index. Enjoy!

like image 143
Dmytro Trofymenko Avatar answered May 19 '26 02:05

Dmytro Trofymenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!