Post

Replies

Boosts

Views

Activity

List freezes after pushing from a navigation link nested in a parent List (MacCatalyst Only)
Background Hi, I've been working with MacCatalyst to build a universal app, however I've run into a problem (perhaps a bug?) with SwiftUI's List component. I think I'm implementing the list correctly as I've looked at Apple's and Paul Hudson's examples and a few others to make sure I was implementing the list correctly. This only occurs when building a target for MacCatalyst. The code works fine on iPhones (real devices and simulators). Problem I make a parent list inside of a NavigationView, call it “List A”, which acts as a sidebar in MacCatalyst. Each item in List A is a NavigationLink. One of these NavigationLink’s destination view is a view containing another list (List B). When navigating to list B, it typically freeze up after an initial scroll or two. After it freezes, the only way to unfreeze it is to either pop out of the view and push back in, sometimes resize the window, or add/remove something from the list. Minimal Reproducible Example The steps below are for a minimal reproducible example: New Xcode project using the UIKit LifeCycle and SwiftUI Interface Tick the MacCatalyst option Add scene delegate code Add all other code into one file Notes • Sometimes its scrolls fine for a little bit, but eventually it always freezes. • The CPU is 0% after freeze but then goes to a typical %15 percent when trying to scroll while frozen. • The list is the only piece of UI that freezes, everything else is functional. Scene Delegate Code func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { &#9;&#9;&#9;&#9;let rootVM = RootView.ViewModel() &#9;&#9;&#9;&#9;// Use a UIHostingController as window root view controller. &#9;&#9;&#9;&#9;if let windowScene = scene as? UIWindowScene { &#9;&#9;&#9;&#9;&#9;&#9;let window = UIWindow(windowScene: windowScene) &#9;&#9;&#9;&#9;&#9;&#9;window.rootViewController = UIHostingController(rootView: RootView(vm: rootVM)) &#9;&#9;&#9;&#9;&#9;&#9;self.window = window &#9;&#9;&#9;&#9;&#9;&#9;window.makeKeyAndVisible() &#9;&#9;&#9;&#9;} &#9;&#9;} All Other Code struct RootView: View { &#9;&#9; &#9;&#9;@ObservedObject var vm:ViewModel &#9;&#9; &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;NavigationView { &#9;&#9;&#9;&#9;&#9;&#9;List { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach(vm.roles, id: \.rawValue) { role in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;NavigationLink( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;role.rawValue, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;destination: viewForRole(role: role) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;.navigationViewStyle(StackNavigationViewStyle()) &#9;&#9;&#9;&#9;.navigationBarTitle("Roles") &#9;&#9;} &#9;&#9; &#9;&#9;@ViewBuilder func viewForRole(role: ViewModel.Role) -> some View { &#9;&#9;&#9;&#9;if role == .admin { &#9;&#9;&#9;&#9;&#9;&#9;QueryView(vm: QueryView.ViewModel()) &#9;&#9;&#9;&#9;}else if role == .moderator { &#9;&#9;&#9;&#9;&#9;&#9;Text("Coming soon!") &#9;&#9;&#9;&#9;}else{ &#9;&#9;&#9;&#9;&#9;&#9;Text(role.rawValue) &#9;&#9;&#9;&#9;} &#9;&#9;} } extension RootView { &#9;&#9; &#9;&#9;class ViewModel:ObservableObject { &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;@Published var roles:[Role] &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;enum Role:String, CaseIterable { &#9;&#9;&#9;&#9;&#9;&#9;case admin = "Admin" &#9;&#9;&#9;&#9;&#9;&#9;case moderator = "Moderator" &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;init() { &#9;&#9;&#9;&#9;&#9;&#9;self.roles = Role.allCases &#9;&#9;&#9;&#9;} &#9;&#9;} } struct QueryView:View { &#9;&#9; &#9;&#9;@ObservedObject var vm:ViewModel &#9;&#9; &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;VStack(alignment: .center) { &#9;&#9;&#9;&#9;&#9;&#9;TextField("Search", text: $vm.searchValue) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.textFieldStyle(RoundedBorderTextFieldStyle()) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.frame(maxWidth: 250) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.padding() &#9;&#9;&#9;&#9;&#9;&#9;List { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach(0..<vm.models.count, id: \.self) { i in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text(vm.models[i]) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;Button("Add Model") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;vm.addModel() &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;.padding() &#9;&#9;&#9;&#9;} &#9;&#9;} &#9;&#9; } extension QueryView { &#9;&#9; &#9;&#9;class ViewModel:ObservableObject { &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;@Published var models:[String] &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;@Published var searchValue:String &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;init() { &#9;&#9;&#9;&#9;&#9;&#9;self.searchValue = "Just for looks..." &#9;&#9;&#9;&#9;&#9;&#9;self.models = [String]() &#9;&#9;&#9;&#9;&#9;&#9;for i in 0..<20 { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;models.append("Model \(i+1)") &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;func addModel() { &#9;&#9;&#9;&#9;&#9;&#9;self.models.append("Model \(models.count + 1)") &#9;&#9;&#9;&#9;} &#9;&#9;} }
3
0
2.3k
Jan ’21