Иногда нам нужно сформировать SwiftUI View с учетом некоторых условий.
Например, в приведенном выше коде мы определяем ГлавнаяПросмотр , который может содержать Просмотр профиля , в случае Логинманагер Есть loggedInUser .
Мы пытаемся реализовать это с помощью стандартного оператора if:
К сожалению, этот код выдаст ошибку при компиляции:struct HomeView: View { @ObservedObject var loginManager: LoginManager var body: some View { VStack { if let user = loginManager.loggedInUser { ProfileView(user: user) } .
} } }
Замыкание, содержащее оператор потока управления, нельзя использовать с построителем функций ViewBuilder.Поскольку здесь используются не обычные замыкатели, а конструкторы функций , мы не можем поместить в них произвольный код для формирования HStack или VStack. Так как же нам выйти из этой ситуации? Один из способов — перенести обработку таких опционалов непосредственно в создаваемые нами представления.
Например, мы можем передать в наш ProfileView не конкретное значение User, а сделать его необязательным: struct ProfileView: View {
var user: User?
var body: some View {
guard let user = user else {
// We have to use 'AnyView' to perform type erasure here,
// in order to give our 'body' a single return type:
return AnyView(EmptyView())
}
return AnyView(VStack {
Text(user.name)
.
})
}
}
Этот код работает, но он не особенно красив.
Нет смысла создавать ProfileView для пользователя nil. Давайте воспользуемся другим подходом: мы используем карта нашему дополнительному пользователю, чтобы преобразовать его в ProfileView: struct HomeView: View {
@ObservedObject var loginManager: LoginManager
var body: some View {
VStack {
loginManager.loggedInUser.map { user in
ProfileView(user: user)
}
.
}
}
}
Это намного удобнее: нам не нужно вручную указывать EmptyView, если у User нет значения.
Мы также можем снова передать в ProfileView конкретное значение, а не необязательное.
Можно ли сделать еще лучше? Хорошие новости о @ViewBuilder заключается в том, что это не какая-то проприетарная реализация в SwiftUI, а общедоступный атрибут, с помощью которого мы можем аннотировать наши собственные функции и замыкания.
Используя этот атрибут, мы можем собрать представление Unwrap, которое принимает в качестве параметров необязательное значение и помеченный параметр.
@ViewBuilder Замыкание для преобразования ненулевого значения в представление: struct Unwrap<Value, Content: View>: View {
private let value: Value?
private let contentProvider: (Value) -> Content
init(_ value: Value?,
@ViewBuilder content: @escaping (Value) -> Content) {
self.value = value
self.contentProvider = content
}
var body: some View {
value.map(contentProvider)
}
}
Используя эту конструкцию, мы теперь можем полностью перепроектировать всю структуру HomeView: struct HomeView: View {
@ObservedObject var loginManager: LoginManager
var body: some View {
VStack {
Unwrap(loginManager.loggedInUser) { user in
HStack {
Text("Logged in as:")
ProfileView(user: user)
}
}
.
}
}
}
Теги: #Разработка для iOS #Разработка для MacOS #Swift #swiftUI #swift. дополнительные виды
-
Создание Плана Резервного Копирования
19 Oct, 24 -
Проблемы Исследования Ключевых Слов Overture
19 Oct, 24 -
Юнек Тайфун Q500 4K
19 Oct, 24 -
Конверт На 4 Диска А4.
19 Oct, 24