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()
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744270904a4566096.html
评论列表(0条)