admin管理员组

文章数量:1401247

I'm rendering a file in my SwiftUI MacOS app, using an AttributedString for syntax highlighting (the AttributedString is computed outside of the rendering loop). As soon as the file is a bit long (20KB in my case) the Text view hangs for around 1s. Even displaying just a String takes 0.1s which is really bad given the simple task. What are my options to address this performance issue? I noticed that giving a fixed frame size to the Text view helps a bit (-30%) (I could do that as I'm using a fix sized font).

Would falling back to UIKit give me better performance?


import HighlightSwift
import Observation
import SwiftUI

// MARK: - Highlighter

@Observable
final class Highlighter {
  init(_ content: String) {
    self.content = content
    Task {
      attributedString = try await highlight.attributedText(content, language: .swift)
    }
  }

  private(set) var attributedString: AttributedString?

  private let content: String
  private let highlight = Highlight()
}

// MARK: - ContentView

struct ContentView: View {
  init() {
    highlighter = Highlighter(fileContent)
  }

  var body: some View {
    VStack {
      HStack {
        Button(action: {
          isExpanded.toggle()
        }, label: {
          Text(isExpanded ? "Collapse" : "Expand")
        })
        Button(action: {
          displayAttributedString.toggle()
        }, label: {
          Text(displayAttributedString ? "use String" : "use AttributedString")
        })
      }
      if isExpanded {
        if displayAttributedString {
//          ScrollView {
            InstrumentedView {
              Text(highlighter.attributedString ?? "")
                .font(.system(size: 12, weight: .regular, design: .monospaced))
            }
//          }
        } else {
//          ScrollView {
            InstrumentedView {
              Text(content)
                .font(.system(size: 12, weight: .regular, design: .monospaced))
            }
//          }
        }
      }
      Spacer(minLength: 0)
    }
    .padding()
  }

  var content: String {
    fileContent
  }

  @State private var displayAttributedString = false
  @State private var isExpanded = false

  @Bindable private var highlighter: Highlighter
}

// MARK: - InstrumentedView

struct InstrumentedView<Content: View>: View {
  init(build: @escaping () -> Content) {
    self.build = build
    print("init")
  }

  let build: () -> Content

  var body: some View {
    VStack {
      if let renderingTime {
        Text("Displayed in: \(renderingTime)s")
      }
      build()
    }.onAppear {
      print("appeared")
      renderingTime = Date().timeIntervalSince(creationDate)
    }
  }

  @State private var renderingTime: TimeInterval?

  private let creationDate = Date()
}

本文标签: swiftRendering a long string in a Text View takes foreverStack Overflow