NavigationStack: czym jest, stos nawigacyjny w SwiftUI

Autor: IT Sectr Opublikowano: 2026-06-24 Czas czytania: 6 min

NavigationStack to nowoczesny kontener nawigacyjny w SwiftUI, wprowadzony w iOS 16+ i zastępujący NavigationView. Według Apple Developer Documentation, 2024, NavigationStack zarządza stosem ekranów poprzez typowo bezpieczną ścieżkę nawigacji (NavigationPath), obsługuje głęboką nawigację, programowy powrót do ekranu głównego i zachowanie stanu przy zmianie danych. W przeciwieństwie do NavigationView, NavigationStack nie wymaga owijania w dodatkowy kontener i udostępnia bezpośrednie wiązanie (Binding) do ścieżki nawigacji.

Najważniejsze

  • NavigationStack — nowy kontener nawigacyjny SwiftUI (iOS 16+)
  • NavigationPath — typowo bezpieczna ścieżka do zarządzania stosem ekranów
  • Deep linking — obsługa programowej nawigacji przez ścieżkę
  • NavigationDestination — rejestracja docelowych ekranów według typów danych
  • Stan nawigacji jest zapisywany i przywracany automatycznie

Czym jest NavigationStack w SwiftUI?

NavigationStack to kontenerowe View implementujące nawigację opartą na stosie (LIFO). Zarządza historią przejść, pozwalając umieszczać nowe ekrany na stosie i wracać za pomocą systemowego przycisku «Wstecz» lub programowo. NavigationStack jest częścią SwiftUI od iOS 16, iPadOS 16, macOS 13, watchOS 9 i tvOS 16.

Główną nowością NavigationStack jest typowo bezpieczna ścieżka nawigacji. Zamiast bezpośredniego wskazywania destination podczas tworzenia NavigationLink, umieszczasz w ścieżce wartość (value), a rejestracja docelowego View odbywa się osobno przez modyfikator .navigationDestination(for:destination:). To rozdziela nawigację i wyświetlanie, czyniąc kod bardziej modułowym i testowalnym.

Według WWDC 2022 (Session 10054), NavigationStack używa nowego mechanizmu nawigacji opartego na ObservableObject i cyklu życia SwiftUI. W przeciwieństwie do NavigationView, który opierał się na UINavigationController pod maską, NavigationStack jest w pełni zaimplementowany w SwiftUI, co poprawia przewidywalność i kompatybilność z cyklem życia SwiftUI.

Podstawowa struktura NavigationStack

NavigationStack przyjmuje główne View i opcjonalną ścieżkę nawigacji (Binding do NavigationPath lub tablicy wartości Hashable). Wszystkie podrzędne ekrany są umieszczane w stosie przez NavigationLink lub programowe dodawanie wartości do ścieżki.

NavigationView był głównym kontenerem nawigacyjnym SwiftUI do iOS 16. Automatycznie zarządzał UINavigationController pod maską, co prowadziło do szeregu problemów: nieprzewidywalne zachowanie przy zmianie danych, trudności z programową nawigacją i brak typowego bezpieczeństwa.

CechaNavigationStack (iOS 16+)NavigationView (iOS 13–15)
Typ nawigacjiStos (LIFO)Stos (LIFO)
Ścieżka nawigacjiTypowana (NavigationPath)Nieobsługiwana
Deep linkingWbudowana obsługaWymaga hacków
Programowy powrótPrzez ścieżkę (pop, popToRoot)dismiss, presentationMode
Pod maskąSwiftUI nativeUINavigationController
KompatybilnośćiOS 16+iOS 13+

Kluczowa zaleta NavigationStack — typowo bezpieczna nawigacja. Definiujesz ścieżkę jako tablicę konkretnych typów (lub NavigationPath dla heterogenicznych stosów) i rejestrujesz destination dla każdego typu. To eliminuje błędy niezgodności typów i czyni nawigację przewidywalną.

NavigationView jest przestarzały w iOS 17. Apple zaleca migrację na NavigationStack dla wszystkich nowych projektów oraz przy aktualizacji minimalnej wersji do iOS 16.

NavigationPath to typ reprezentujący ścieżkę nawigacji w NavigationStack. Może przechowywać wartości heterogeniczne (AnyHashable) lub być używany z konkretnym typem przez Binding do tablicy [T: Hashable]. NavigationPath automatycznie się koduje i dekoduje w celu zachowania stanu.

swift
struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            HomeView()
                .navigationDestination(for: String.self) { value in
                    DetailView(id: value)
                }
                .navigationDestination(for: Int.self) { value in
                    NumberView(number: value)
                }
        }
    }

    func goToRoot() {
        path.removeLast(path.count)
    }

    func pushDeepLink() {
        path.append("detail_42")
    }
}

Stos heterogeniczny: NavigationPath może zawierać wartości różnych typów, jeśli implementują Hashable. Na przykład pierwszy ekran może przyjmować String (ID), drugi — Int (numer), trzeci — niestandardowy enum Route. Do wyświetlenia każdego typu rejestruje się osobny .navigationDestination.

Obsługa Codable: NavigationPath implementuje Codable, jeśli wszystkie wartości w ścieżce są również Codable + Hashable. Pozwala to zapisywać i przywracać stan nawigacji przy ponownym uruchomieniu aplikacji lub przejściu do trybu tła.

.navigationDestination(for:destination:) — modyfikator rejestrujący docelowe View dla konkretnego typu danych. Gdy NavigationLink umieszcza w ścieżce wartość tego typu, SwiftUI automatycznie znajduje odpowiedni .navigationDestination i tworzy ekran.

swift
enum AppRoute: Hashable {
    case profile(UserID)
    case settings
    case about
}

struct AppNavigation: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            HomeView()
                .navigationDestination(for: AppRoute.self) { route in
                    switch route {
                    case .profile(let id):
                        ProfileView(userId: id)
                    case .settings:
                        SettingsView()
                    case .about:
                        AboutView()
                    }
                }
        }
    }
}

// Navigate: path.append(AppRoute.profile("user_123"))

Ważna zasada: .navigationDestination musi być zastosowany do View, które znajduje się wewnątrz NavigationStack, i zanim NavigationLink umieści wartość w ścieżce. Zwykle dodaje się go do głównego View lub do kontenera sekcji. Jeśli .navigationDestination nie zostanie znaleziony dla typu wartości, przejście nie nastąpi.

Według SwiftUI Engineering (2023), .navigationDestination może być zarejestrowany na różnych poziomach hierarchii. SwiftUI szuka najbliższego pasującego destination przy próbie nawigacji. Pozwala to nadpisywać destination dla jednego typu w różnych częściach aplikacji.

Wzorzec 1: nawigacja przez enum Route. Zdefiniuj enum z wartościami powiązanymi dla wszystkich ekranów aplikacji. Użyj jednego .navigationDestination dla AppRoute i switch do routingu. Zapewnia to jeden źródło prawdy dla wszystkich możliwych przejść w aplikacji.

swift
struct StoreView: View {
    @State private var path: [ProductRoute] = []

    var body: some View {
        NavigationStack(path: $path) {
            ProductGrid()
                .navigationDestination(for: ProductRoute.self) { route in
                    switch route {
                    case .detail(let product):
                        ProductDetail(product: product)
                    case .reviews(let productId):
                        ReviewsView(productId: productId)
                    }
                }
        }
    }
}

enum ProductRoute: Hashable {
    case detail(Product)
    case reviews(String)
}

Wzorzec 2: programowa nawigacja i deep linking. NavigationStack pozwala programowo zarządzać stosem: dodawać, usuwać ekrany i wracać do korzenia. Jest to niezbędne dla powiadomień push, linków głębokich i przywracania nawigacji po ponownym uruchomieniu.

Wzorzec 3: tablica typów zamiast NavigationPath. Jeśli wszystkie ekrany używają jednego typu (np. String lub niestandardowy enum), użyj Binding do [T]. Daje to bardziej rygorystyczną typizację i lepszą wydajność niż NavigationPath. NavigationPath jest uzasadniony dla heterogenicznych stosów z różnymi typami ekranów.

Według Point-Free (2024), NavigationStack z enum Route to preferowany sposób organizacji nawigacji w aplikacjach SwiftUI. Czyni wszystkie możliwe przejścia jawnymi, typowo bezpiecznymi i testowalnymi, co jest szczególnie ważne dla dużych projektów z dziesiątkami ekranów.

Często zadawane pytania

Czym jest NavigationStack w SwiftUI?

NavigationStack to kontener nawigacyjny SwiftUI (iOS 16+), zarządzający stosem ekranów przez typowo bezpieczną ścieżkę. Zastąpił NavigationView, oferując obsługę deep linkingu, programowej nawigacji i zapisywania stanu.

Czym NavigationStack różni się od NavigationView?

NavigationStack używa typowo bezpiecznej ścieżki (NavigationPath) zamiast bezpośredniego łączenia NavigationLink z destination. Obsługuje programową nawigację, deep linking i Codable do zapisywania stanu. Działa na SwiftUI, a nie przez UINavigationController.

Jak działa NavigationPath?

NavigationPath to typ reprezentujący sekwencję ekranów w stosie. Dodajesz wartości do ścieżki przez path.append() lub przez NavigationLink z value. Do wyświetlenia każdego typu rejestruje się .navigationDestination. NavigationPath obsługuje Codable i automatyczne zapisywanie stanu.

Jak zaimplementować deep linking z NavigationStack?

Przez programowe zarządzanie ścieżką: po przetworzeniu URL wywołaj path.append() z odpowiednią wartością trasy. NavigationStack automatycznie wyświetli docelowy ekran. Powrót do korzenia — path.removeLast(path.count).

Czy trzeba migrować z NavigationView na NavigationStack?

Tak, jeśli Twoja minimalna wersja to iOS 16+. NavigationView jest przestarzały w iOS 17. Migracja daje typowo bezpieczną nawigację, obsługę deep linkingu i lepsze dopasowanie do cyklu życia SwiftUI. Dla projektów z iOS 15 i niżej nadal używaj NavigationView.

Podsumowanie

  • NavigationStack — nowoczesny kontener nawigacyjny SwiftUI (iOS 16+)
  • NavigationPath — typowo bezpieczna ścieżka do zarządzania stosem ekranów
  • NavigationDestination — rejestracja docelowych View według typów danych
  • NavigationView przestarzały w iOS 17, migracja zalecana
  • Deep linking i programowa nawigacja — wbudowana obsługa
  • Enum Route — preferowany wzorzec organizacji nawigacji
  • Stos heterogeniczny przez NavigationPath z dowolnymi typami Hashable

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również