SwiftUI и Swift 5.7: проблема с протоколом просмотра и непрозрачными типами
У меня возникает ошибка компиляции, когда я пытаюсь вернуть из метода разные пользовательские представления, соответствующие протоколу представления. Вот простой пример, описывающий проблему.
Я хочу иметь метод, который возвращает другое пользовательское представление на основе случая перечисления. Когда я пытаюсь добиться этого, я получаю разные ошибки компиляции:
enum AppScreen: String, CaseIterable {
case home
case detail
}
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getSomeView(screen)) {
Text(screen.rawValue)
}
}
}
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getAnyView(screen)) {
Text(screen.rawValue)
}
}
}
}
}
private func getSomeView(_ screen: AppScreen) -> some View {
switch screen {
case .home:
return HomeView()
case .detail:
return DetailView()
}
}
private func getAnyView(_ screen: AppScreen) -> any View {
switch screen {
case .home:
return HomeView()
case .detail:
return DetailView()
}
}
}
Метод getSomeView выдает следующую ошибку компиляции: Функция объявляет непрозрачный тип возвращаемого значения «некоторый вид», но операторы возврата в ее теле не имеют соответствующих базовых типов.
Метод getAnyView компилируется, но я получаю следующую ошибку, когда вызываю его в качестве места назначения для NavigationLink: Тип «любой вид» не может соответствовать «Вид»
Я изучаю SwiftUI и новые функции дженериков из Swift 5.7. Я считаю, что поведение, которое я ищу, может быть достигнуто. Любая помощь или руководство будут оценены, спасибо заранее!
1 ответ
Вот как добиться того, что вы пытаетесь сделать.
- Отметка
getSomeView()
с@ViewBuilder
. Это заставляет его работать какvar body
который также являетсяViewBuilder
позволяет создавать различные типы представлений. - Удалить
return
заявления.
Вот отдельный пример, основанный на вашем исходном коде:
enum AppScreen: String, CaseIterable {
case home
case detail
}
struct HomeView: View {
var body: some View {
Text("HomeView")
}
}
struct DetailView: View {
var body: some View {
Text("DetailView")
}
}
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getSomeView(screen)) {
Text(screen.rawValue)
}
}
}
}
}
@ViewBuilder
private func getSomeView(_ screen: AppScreen) -> some View {
switch screen {
case .home:
HomeView()
case .detail:
DetailView()
}
}
}