NSTextStorage с длинным текстом внутри. Спектакль

У меня есть NSTextStorage с длинным текстом внутри (например, 500 страниц в книге и более 9000 на устройстве для текущего шрифта). Я распространяю этот текст для текстовых контейнеров следующим образом:

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

Проблема в том, что для инициализации всех этих контейнеров и т. Д. Требуется много времени. Я уже внес некоторые улучшения, такие как изменение кода при использовании

while lastRenderedGlyph < layoutManager!.numberOfGlyphs {

а также

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

cz он работает намного медленнее.

Итак, какие еще улучшения я могу сделать? На iPhone 7 инициализация занимает около 7 секунд, на iPhone 5s 20 секунд +

Профилировщик времени показывает, что практически все время получает функцию insertTextContainer (addTextContainer).

Какие-либо предложения?

1 ответ

Решение

Менеджер макетов делает недействительным макет на addTextContainer вызов метода и перестраивает макет на textContainer(forGlyphAt:effectiveRange:), Вы можете проверить это, установив делегата для менеджера по расположению и наблюдая layoutManagerDidInvalidateLayout, Поэтому вместо того, чтобы делать макет один раз, вы делаете это 500 раз - один раз для каждого добавленного текстового контейнера.

Вы можете добавлять текстовые контейнеры в пакетах, чтобы уменьшить количество макетов, например

  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

Пустые текстовые контейнеры в конце вы можете оставить или удалить, начиная с последнего индекса текстового контейнера. Наслаждайтесь!

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