Я хотел бы знать, является ли поведение onAppear и onDisappear в SwiftUI (Xcode 11 beta 6, когда я писал это) более полезным для разработчика, или это просто больше проблема, чем функция.
Прямо сейчас, если мы будем использовать каскадную навигацию, как вы найдете в примере кода, который я прилагаю (который компилируется и отлично работает в Xcode 11b6), вывод консоли пользователя, перемещающегося вперед и назад, будет просто запускать onAppear только в случае новый вид нагрузки в прямом направлении (имеется в виду углубление).
В навигации: Root -> NestedView1 -> NestedView2 -> NestedView3, при добавлении помощника отладки на каждую стадию просмотра,
.onAppear(perform: {print("onAppear level N")})
.onDisappear(perform: {print("onDisappear level N")})
консоль отладки покажет
onAppear root level 0
onAppear level 1
onAppear level 2
onAppear level 3
(Нет триггера onDisappear)
но возвращаясь обратно Root ‹- NestedView1‹ - NestedView2 ‹- NestedView3
консоль отладки не покажет ... ничего
(Нет запуска onAppear или onDisappear)
struct NestedViewLevel3: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack {
Spacer()
Text("Level 3")
Spacer()
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Back")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.blue)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
}
Spacer()
}
.navigationBarBackButtonHidden(false)
.navigationBarTitle("Level 3", displayMode: .inline)
.onAppear(perform: {print("onAppear level 3")})
.onDisappear(perform: {print("onDisappear level 3")})
}
}
struct NestedViewLevel2: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack {
Spacer()
NavigationLink(destination: NestedViewLevel3()) {
Text("To level 3")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.gray)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
.shadow(radius: 10)
}
Spacer()
Text("Level 2")
Spacer()
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Back")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.blue)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
}
Spacer()
}
.navigationBarBackButtonHidden(false)
.navigationBarTitle("Level 2", displayMode: .inline)
.onAppear(perform: {print("onAppear level 2")})
.onDisappear(perform: {print("onDisappear level 2")})
}
}
struct NestedViewLevel1: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack {
Spacer()
NavigationLink(destination: NestedViewLevel2()) {
Text("To level 2")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.gray)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
.shadow(radius: 10)
}
Spacer()
Text("Level 1")
Spacer()
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Back")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.blue)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
}
Spacer()
}
.navigationBarBackButtonHidden(false)
.navigationBarTitle("Level 1", displayMode: .inline)
.onAppear(perform: {print("onAppear level 1")})
.onDisappear(perform: {print("onDisappear level 1")})
}
}
struct RootViewLevel0: View {
var body: some View {
NavigationView {
VStack {
Spacer()
NavigationLink(destination: NestedViewLevel1()) {
Text("To level 1")
.padding(.horizontal, 15)
.padding(.vertical, 2)
.foregroundColor(Color.white)
.clipped(antialiased: true)
.background(
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color.gray)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
)
.shadow(radius: 10)
}
Spacer()
}
}
.navigationBarTitle("Root level 0", displayMode: .inline)
.navigationBarBackButtonHidden(false)
.navigationViewStyle(StackNavigationViewStyle())
.onAppear(perform: {print("onAppear root level 0")})
.onDisappear(perform: {print("onDisappear root level 0")})
}
}
struct ContentView: View {
var body: some View {
RootViewLevel0()
}
}
}
Теперь разработчик предпочел бы onAppear и onDisappear:
1) Запускается с целью запуска действий, которые необходимо выполнить только один раз и только тогда, когда пользователь движется вперед, как в текущем наблюдаемом поведении.
2) Срабатывает каждый раз, когда появляется представление, больше похоже на название действия, которое, по-видимому, означает, будь то назад, вперед и любое количество раз.
Я бы выбрал вариант 2, простой и жестокий (и то, что мне сейчас нужно), но я довольно наивный новичок в NavigationView, и вариант 2 может нарушить многие устоявшиеся парадигмы, которые я не принимаю во внимание.
Ваш отзыв поможет мне узнать, обоснован ли соответствующий случай использования Feedback Assistant для SwiftUI на законных основаниях.