I made a small project that freezes after the following steps:
- Run the app
- Turn on VoiceOver
- Tap on "Header" once so it is read out loud
- Turn off VoiceOver
- Scroll up and down really quickly
Using the Time Profiler, the items in the Main Thread followed by significant drops are:
- 19.11 s 85.1% 0 s closure #2 in closure #1 in ViewRendererHost.render(interval:updateDisplayList:targetTimestamp:)
- 13.05 s 58.1% 4.00 ms ViewGraph.updateOutputs(async:)
- 7.97 s 35.5% 83.00 ms AG::Graph::UpdateStack::update()
- 5.76 s 25.6% 19.00 ms LayoutScrollableTransform.updateValue()
- 1.73 s 7.7% 2.00 ms specialized NativeDictionary.setValue(:forKey:isUnique:)
- 579.00 ms 2.6% 58.00 ms 0x100a8c908
- 311.00 ms 1.4% 165.00 ms __thread_stack_pcs
I see the memory usage increase by about 0.6 MB per second while frozen.
And there are a few things that prevent the freeze:
- Changing
LazyVStack
forVStack
- Removing the
VStack
from theSection
- Removing the
header:
parameter from theSection
- Reducing the range of the
ForEach
- Move the
Text(verbatim: "Text at same level as ForEach containing Section")
outside of the LazyVStack
However, these are all things I need to keep for my actual app. So what is causing this hang? Am I using SwiftUI in any way it's not intended to be used?
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
VStack(alignment: .leading) {
Image(systemName: "pencil.circle.fill")
Text("Title")
Text("Label")
}
ScrollView {
LazyVStack {
Section {
VStack {
ForEach(0..<70) { _ in
Text(verbatim: "A")
}
}
} header: {
Text(verbatim: "Header")
}
Text(verbatim: "Text at same level as ForEach containing Section")
}
}
}
}
}
AppDelegate:
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UINavigationController(rootViewController: MainViewController())
window.makeKeyAndVisible()
self.window = window
return true
}
}
MainViewController:
import UIKit
import SwiftUI
final class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swiftUIView = ContentView()
let hostingController = UIHostingController(rootView: swiftUIView)
addChild(hostingController)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
hostingController.didMove(toParent: self)
view.backgroundColor = .white
}
}