Ian
Ian

Reputation: 43

Unexpected warning: Someone is removing an active search controller while its search bar is visible

I have a largish app with a deep navigation stack. I display a list of items and filter with .searchable. When an item is selected using a search I get the following messages:

List failed to visit cell content, returning an empty cell. - SwiftUI/UICollectionViewListCoordinator.swift:367 - please file a bug report.

List failed to visit cell content, returning an empty cell. - SwiftUI/UICollectionViewListCoordinator.swift:367 - please file a bug report.

Someone is removing an active search controller while its search bar is visible. The UI probably looks terrible. Search controller being removed: <SwiftUI.SwiftUISearchController: 0x12c00d800> from navigation item: <UINavigationItem: 0x12d111fd0> style=navigator leftItemsSupplementBackButton

The third message is a warning. The first two are not. Prior to learning and adding dismissSearch() to the code below, I did not get the please file a bug report messages, only the "Someone is removing..." warning.

I have put together a small app that mimics the architecture and reproduces the problem.

If you run the following app, touch "Select something", enter a letter (e.g. k) and then select a row, the warning is displayed.

I am using Xcode Version 15.0.1 (15A507) and running on either an iPhone 15 Simulator iOS 17.0 or a real device (14 pro) on iOS 17.

import SwiftUI

struct ContentView: View {
    @StateObject private var dataService = DataService()
    var body: some View {
        NavigationStack(path: $dataService.path) {
            Form {
                Text("\(dataService.selectedItem ?? "Nothing") selected")
                NavigationLink(value: 1) {
                    Text("Select something")
                }
            }
            .navigationDestination(for: Int.self) { value in
                ListView()
                    .environmentObject(dataService)
                    .searchable(text: $dataService.searchText, placement: .navigationBarDrawer(displayMode: .always))
                
            }
        }
    }
}

struct ListView: View {
    @Environment(\.dismissSearch) private var dismissSearch
    @EnvironmentObject private var dataService: DataService
    var body: some View {
        List(dataService.filteredOptions, id: \.self) { option in
            Button( action: {
                dataService.selectedItem = option
                dismissSearch()
                dataService.path.removeLast()
                
            }) {
                Text(option)
            }
        }
    }
}


class DataService: ObservableObject {
    @Published var path = Array<Int>()
    @Published var selectedItem: String?
    @Published var searchText: String = ""
    var filteredOptions: [String] {
        if searchText.isEmpty {
            return DataService.names
        } else {
            return DataService.names.filter { name in
                name.localizedCaseInsensitiveContains(searchText)
            }
        }
    }
    
    static let names = [
        "Mark",
        "David",
        "John",
        "Pick"
    ]
}

I have tried reordering the button actions. No change. I have tried putting the actions in a Task. No change.

I have tried using dismiss() instead of dataService.path.removeLast(). When I do this the warning disappears but the app becomes unresponsive after the ListView is dismissed.

If I use dismiss without dismissSearch I get the following warning. > Inconsistent state handled when removing old search controller. Investigate if repro steps are available. Otherwise, ignore.

In any case, in my app, I sometimes need to pop several views off the stack, so I need to remove items from the end of the path. I have searched for other references to this but couldn't find the solution.

Upvotes: 2

Views: 424

Answers (0)

Related Questions