Minimalny odtwarzalny przykład (Xcode 11.2 beta, działa w Xcode 11.1):
struct Parent: View {
var body: some View {
NavigationView {
Text("Hello World")
.navigationBarItems(
trailing: NavigationLink(destination: Child(), label: { Text("Next") })
)
}
}
}
struct Child: View {
@Environment(\.presentationMode) var presentation
var body: some View {
Text("Hello, World!")
.navigationBarItems(
leading: Button(
action: {
self.presentation.wrappedValue.dismiss()
},
label: { Text("Back") }
)
)
}
}
struct ContentView: View {
var body: some View {
Parent()
}
}
Problem polega na tym, że umieszczam moje NavigationLink
wnętrze navigationBarItems
modyfikatora zagnieżdżonego w widoku SwiftUI, którego widokiem głównym jest NavigationView
. Raport o awarii wskazuje, że próbuję przejść do kontrolera widoku, który nie istnieje, gdy nawiguję do przodu, Child
a następnie z powrotem do Parent
.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'
*** First throw call stack:
Gdybym zamiast tego umieścił to NavigationLink
w treści widoku, jak poniżej, działa to dobrze.
struct Parent: View {
var body: some View {
NavigationView {
NavigationLink(destination: Child(), label: { Text("Next") })
}
}
}
Czy to błąd SwiftUI lub oczekiwane zachowanie?
EDYCJA: Otworzyłem problem z Apple w ich asystencie zwrotnym z identyfikatorem FB7423964
na wypadek, gdyby ktokolwiek z Apple miał ochotę ważyć :).
EDYCJA: Mój otwarty bilet w asystencie opinii wskazuje, że zgłoszono ponad 10 podobnych problemów. Zaktualizowali rozdzielczość o Resolution: Potential fix identified - For a future OS update
. Trzymałem kciuki, że ta niedługo ląduje.
EDYCJA: Naprawiono to w iOS 13.3!
ContentView.swift
. Zrobię edycję wpisu, ale awaria zdarza się tylko wtedy, gdy nawigujesz do przodu, a następnie do tyłu.Odpowiedzi:
To było dla mnie dość uciążliwe! Zostawiłem to, dopóki większość mojej aplikacji nie została ukończona, i miałem przestrzeń umysłu, aby poradzić sobie z awarią.
Myślę, że wszyscy możemy się zgodzić, że w SwifUI jest kilka niesamowitych rzeczy, ale debugowanie może być trudne.
Moim zdaniem powiedziałbym, że to BŁĄD. Oto moje uzasadnienie:
Jeśli zamkniesz wywołanie trybu prezentacji w trybie asynchronicznym z opóźnieniem wynoszącym około pół sekundy, program powinien przestać się zawieszać.
To sugeruje mi, że błąd jest nieoczekiwanym zachowaniem głęboko w tym, jak SwiftUI łączy się z całym innym kodem UIKit w celu zarządzania różnymi widokami. W zależności od rzeczywistego kodu może się okazać, że jeśli w widoku występuje niewielka złożoność, awaria faktycznie nie nastąpi. Na przykład, jeśli usuwasz widok z widoku, który ma listę, a ta lista jest pusta, nastąpi awaria bez asynchronicznego opóźnienia. Z drugiej strony, jeśli masz tylko jeden wpis w tym widoku listy, co wymusza iterację pętli w celu wygenerowania widoku nadrzędnego, zobaczysz, że awaria nie nastąpi.
Nie jestem do końca pewien, jak solidne jest moje rozwiązanie polegające na opóźnieniu odwołania. Muszę to przetestować o wiele bardziej. Jeśli masz pomysły na ten temat, daj mi znać! Byłbym bardzo szczęśliwy, mogąc uczyć się od ciebie!
źródło
.navigationBarItems()
punktami, jest to błąd.Sfrustrowało mnie to także od dłuższego czasu. W ciągu ostatnich kilku miesięcy, w zależności od wersji Xcode, wersji symulatora oraz rzeczywistego typu i / lub wersji urządzenia, zmieniło się ono z pracy w niedziałającą, ponownie na pozór losowo. Jednak ostatnio mi się to nie udaje, więc wczoraj głęboko się w to zanurzyłem. Obecnie używam Xcode w wersji 11.2.1 (11B500).
Wygląda na to, że problem dotyczy paska nawigacji i sposobu dodania do niego przycisków. Zamiast używać NavigationLink () dla samego przycisku, próbowałem użyć standardowego Button () z akcją, która ustawia zmienną @State, która aktywuje ukryty NavigationLink. Oto zamiennik widoku rodzica Roberta:
Dla mnie działa to bardzo konsekwentnie we wszystkich symulatorach i wszystkich rzeczywistych urządzeniach.
Oto moje widoki pomocników:
Oto przykład użycia:
źródło
Jest to poważny błąd i nie widzę odpowiedniego sposobu na obejście go. Działa dobrze w iOS 13 / 13.1, ale awarie 13.2.
Możesz go replikować w znacznie prostszy sposób (ten kod jest dosłownie wszystkim, czego potrzebujesz).
Mam nadzieję, że Apple to rozwiąże, ponieważ z pewnością zniszczy mnóstwo aplikacji SwiftUI (w tym moich).
źródło
Aby obejść ten problem, w oparciu o powyższą odpowiedź Chucka H, enkapsulowałem NavigationLink jako ukryty element:
Następnie możesz użyć go w widoku nawigacji (co jest kluczowe) i uruchomić go z przycisku na pasku nawigacyjnym:
Zawiń to w komentarze „// HACK”, więc gdy Apple to naprawi, możesz go zastąpić.
źródło
Na podstawie informacji, które przekazaliście, a zwłaszcza komentarza @Robert na temat miejsca, w którym znajduje się NavigationView, znalazłem sposób na obejście tego problemu przynajmniej w moim konkretnym scenariuszu.
W moim przypadku miałem TabView, który był zamknięty w NavigationView w następujący sposób:
Ten kod ulega awarii, ponieważ wszyscy zgłaszają się w systemie iOS 13.2 i działa w systemie iOS 13.1. Po kilku badaniach wymyśliłem obejście tej sytuacji.
Zasadniczo przenoszę NavigationView do każdego ekranu osobno na każdej karcie w następujący sposób:
Jakoś jest sprzeczne z założeniem SwiftUI dotyczącym prostoty, ale działa na iOS 13.2.
źródło
Xcode 11.2.1 Swift 5
ROZUMIEM! Rozpracowanie tego zajęło mi kilka dni ...
W moim przypadku podczas korzystania ze SwiftUI dochodzi do awarii tylko wtedy, gdy spód mojej listy wystaje poza ekran, a następnie próbuję „przenieść” dowolne elementy listy. Ostatecznie dowiedziałem się, że jeśli mam za dużo „rzeczy” pod List (), to ulega awarii podczas przenoszenia. Na przykład poniżej mojej listy () miałem przycisk Tekst (), Odstęp (), Przycisk (), Odstęp ()) (). Gdybym skomentował JEDEN z tych obiektów, nagle nie mogłem odtworzyć awarii. Nie jestem pewien, jakie są ograniczenia, ale jeśli masz awarię, spróbuj usunąć obiekty poniżej listy, aby zobaczyć, czy to pomoże.
źródło
Chociaż nie widzę żadnych awarii, Twój kod ma pewne problemy:
ustawiając wiodący element, faktycznie zabijasz domyślne zachowanie przejść nawigacyjnych. (spróbuj przesunąć palcem od strony wiodącej, aby zobaczyć, czy to działa).
Więc nie trzeba mieć przycisku. Po prostu zostaw to tak, jak jest, a masz bezpłatny przycisk Wstecz.
I nie zapominaj, zgodnie z HIG , tytuł przycisku wstecz powinien pokazywać, dokąd idzie, a nie co to jest! Postaraj się więc ustawić tytuł dla pierwszej strony, aby wyświetlać ją każdemu przyciskowi wstecz, który się na nią pojawi.
źródło
FWIW - powyższe rozwiązania sugerujące ukryty hack NavigationLink to wciąż najlepsze obejście w iOS 13.3b3. Złożyłem również FB7386339 ze względu na potomstwo i został zamknięty podobnie jak inne wyżej wspomniane FB: „Zidentyfikowano potencjalną poprawkę - do przyszłej aktualizacji systemu operacyjnego”.
Skrzyżowane palce.
źródło
Jest rozwiązany w iOS 13.3. Po prostu zaktualizuj system operacyjny i kod xCode.
źródło
.buttonStyle(PlainButtonStyle())
modyfikator NavigationLink i spróbuj ponownie. daj mi znać, jeśli zadałeś pytanie.