SwiftUI'da NavigationStack: Modern Navigasyon Yönetiminin Rehberi

NavigationView'ın yerini alan Apple'ın güçlü yeni navigasyon sistemi NavigationStack'i öğrenin. Pratik örnekler ve en iyi uygulamalarla kapsamlı rehber.

swiftui navigationstack ios16 navigasyon apple geliştirme
SwiftUI'da NavigationStack: Modern Navigasyon Yönetiminin Rehberi

SwiftUI’da NavigationStack: Modern Navigasyon Yönetiminin Rehberi

iOS 16 ile SwiftUI navigasyonunda en önemli gelişmelerden biri tanıtıldı: NavigationStack. Bu güçlü yeni API, eskiyen NavigationView’ın yerini alıyor ve geliştiricilere navigasyon akışları üzerinde eşi görülmemiş kontrol sağlıyor. NavigationStack hakkında bilmeniz gereken her şeyi derinlemesine inceleyelim.

Neden NavigationView Yerine NavigationStack?

🚫 NavigationView’ın Sorunları

NavigationView, geliştiricileri hayal kırıklığına uğratan birçok sınırlamaya sahipti:

// ❌ Eski NavigationView yaklaşımı - kullanımdan kaldırıldı
NavigationView {
    List {
        NavigationLink("Ayarlar", destination: AyarlarView())
        NavigationLink("Profil", destination: ProfilView())
    }
    .navigationTitle("Ana Sayfa")
}
.navigationViewStyle(StackNavigationViewStyle()) // iPad'de gerekli

NavigationView’ın Sorunları:

✅ NavigationStack Avantajları

// ✅ Yeni NavigationStack yaklaşımı
@State private var navigasyonYolu = NavigationPath()

NavigationStack(path: $navigasyonYolu) {
    List {
        Button("Ayarlara Git") {
            navigasyonYolu.append("ayarlar")
        }
        Button("Profile Git") {
            navigasyonYolu.append("profil")
        }
    }
    .navigationDestination(for: String.self) { hedef in
        switch hedef {
        case "ayarlar":
            AyarlarView()
        case "profil":
            ProfilView()
        default:
            EmptyView()
        }
    }
    .navigationTitle("Ana Sayfa")
}

NavigationStack’in Faydaları:

Temel NavigationStack Uygulaması

Basit Navigasyon Örneği

import SwiftUI

struct İçerikGörünümü: View {
    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                NavigationLink("Detay Görünümüne Git") {
                    DetayGörünümü(başlık: "İlk Detay")
                }
                
                NavigationLink("Ayarlara Git") {
                    AyarlarView()
                }
            }
            .navigationTitle("Ana Sayfa")
            .navigationBarTitleDisplayMode(.large)
        }
    }
}

struct DetayGörünümü: View {
    let başlık: String
    
    var body: some View {
        VStack {
            Text("Bu \(başlık)")
                .font(.largeTitle)
            
            NavigationLink("Daha Derine Git") {
                DetayGörünümü(başlık: "İç İçe Detay")
            }
        }
        .navigationTitle(başlık)
        .navigationBarTitleDisplayMode(.inline)
    }
}

Yol Yönetimi ile Gelişmiş NavigationStack

Programatik Navigasyon Kontrolü

NavigationStack’in gerçek gücü, navigasyon durumunu programatik olarak yönetebilme kabiliyetinden gelir:

struct GelişmişNavigasyonÖrneği: View {
    @State private var navigasyonYolu = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigasyonYolu) {
            VStack(spacing: 20) {
                Button("Ayarlara Naviget Et") {
                    navigasyonYolu.append(Hedef.ayarlar)
                }
                
                Button("Profile Naviget Et") {
                    navigasyonYolu.append(Hedef.profil)
                }
                
                Button("İç İçe Görünüme Deep Link") {
                    // Birden fazla ekranda aynı anda navigasyon
                    navigasyonYolu.append(Hedef.ayarlar)
                    navigasyonYolu.append(AyarlarBölümü.gizlilik)
                    navigasyonYolu.append(GizlilikSeçeneği.veriPaylaşımı)
                }
                
                Button("Geri Git") {
                    if !navigasyonYolu.isEmpty {
                        navigasyonYolu.removeLast()
                    }
                }
                
                Button("Ana Sayfaya Git") {
                    navigasyonYolu = NavigationPath()
                }
            }
            .navigationTitle("Gelişmiş Navigasyon")
            .navigationDestination(for: Hedef.self) { hedef in
                hedefGörünümü(for: hedef)
            }
            .navigationDestination(for: AyarlarBölümü.self) { bölüm in
                AyarlarBölümGörünümü(bölüm: bölüm)
            }
            .navigationDestination(for: GizlilikSeçeneği.self) { seçenek in
                GizlilikSeçenekGörünümü(seçenek: seçenek)
            }
        }
    }
    
    @ViewBuilder
    private func hedefGörünümü(for hedef: Hedef) -> some View {
        switch hedef {
        case .ayarlar:
            AyarlarAnaGörünümü(navigasyonYolu: $navigasyonYolu)
        case .profil:
            ProfilView()
        }
    }
}

enum Hedef: Hashable {
    case ayarlar
    case profil
}

enum AyarlarBölümü: String, Hashable, CaseIterable {
    case gizlilik = "Gizlilik"
    case güvenlik = "Güvenlik"
    case bildirimler = "Bildirimler"
}

enum GizlilikSeçeneği: String, Hashable, CaseIterable {
    case veriPaylaşımı = "Veri Paylaşımı"
    case analitik = "Analitik"
    case çerezler = "Çerezler"
}

Özel Türlerle Tip Güvenli Navigasyon

Sağlam Navigasyon Modelleri Oluşturma

class NavigasyonModeli: ObservableObject {
    @Published var yol = NavigationPath()
    
    func kullanıcıProfilineNavigetEt(_ kullanıcıID: String) {
        yol.append(NavigasyonHedefi.kullanıcıProfili(kullanıcıID))
    }
    
    func gönderiyeNavigetEt(_ gönderiID: Int) {
        yol.append(NavigasyonHedefi.gönderi(gönderiID))
    }
    
    func anaKökeGit() {
        yol = NavigationPath()
    }
    
    func geriGit() {
        if !yol.isEmpty {
            yol.removeLast()
        }
    }
}

enum NavigasyonHedefi: Hashable {
    case kullanıcıProfili(String)
    case gönderi(Int)
    case ayarlar
    case profilDüzenle
    
    // Daha iyi performans için özel hash uygulaması
    func hash(into hasher: inout Hasher) {
        switch self {
        case .kullanıcıProfili(let id):
            hasher.combine("kullanıcıProfili")
            hasher.combine(id)
        case .gönderi(let id):
            hasher.combine("gönderi")
            hasher.combine(id)
        case .ayarlar:
            hasher.combine("ayarlar")
        case .profilDüzenle:
            hasher.combine("profilDüzenle")
        }
    }
}

struct AnaNavigasyonGörünümü: View {
    @StateObject private var navigasyonModeli = NavigasyonModeli()
    
    var body: some View {
        NavigationStack(path: $navigasyonModeli.yol) {
            İçerikListeGörünümü(navigasyonModeli: navigasyonModeli)
                .navigationDestination(for: NavigasyonHedefi.self) { hedef in
                    hedefGörünümü(for: hedef)
                }
        }
        .environmentObject(navigasyonModeli)
    }
    
    @ViewBuilder
    private func hedefGörünümü(for hedef: NavigasyonHedefi) -> some View {
        switch hedef {
        case .kullanıcıProfili(let kullanıcıID):
            KullanıcıProfilGörünümü(kullanıcıID: kullanıcıID)
        case .gönderi(let gönderiID):
            GönderiDetayGörünümü(gönderiID: gönderiID)
        case .ayarlar:
            AyarlarView()
        case .profilDüzenle:
            ProfilDüzenleGörünümü()
        }
    }
}

Gerçek Dünya Örnekleri

Sosyal Medya Uygulaması Navigasyonu

struct SosyalMedyaNavigasyonu: View {
    @State private var navigasyonYolu = NavigationPath()
    @State private var seçiliTab = 0
    
    var body: some View {
        TabView(selection: $seçiliTab) {
            NavigationStack(path: $navigasyonYolu) {
                AkışGörünümü { gönderi in
                    navigasyonYolu.append(SosyalRota.gönderiDetayı(gönderi))
                }
                .navigationTitle("Akış")
                .navigationDestination(for: SosyalRota.self) { rota in
                    sosyalHedef(for: rota)
                }
            }
            .tabItem {
                Image(systemName: "house.fill")
                Text("Ana Sayfa")
            }
            .tag(0)
            
            NavigationStack {
                ProfilView { aksiyon in
                    profilAksiyonuİşle(aksiyon)
                }
                .navigationTitle("Profil")
            }
            .tabItem {
                Image(systemName: "person.fill")
                Text("Profil")
            }
            .tag(1)
        }
    }
    
    @ViewBuilder
    private func sosyalHedef(for rota: SosyalRota) -> some View {
        switch rota {
        case .gönderiDetayı(let gönderi):
            GönderiDetayGörünümü(gönderi: gönderi) { kullanıcı in
                navigasyonYolu.append(SosyalRota.kullanıcıProfili(kullanıcı))
            }
        case .kullanıcıProfili(let kullanıcı):
            KullanıcıProfilGörünümü(kullanıcı: kullanıcı)
        case .yorumlar(let gönderi):
            YorumlarGörünümü(gönderi: gönderi)
        }
    }
    
    private func profilAksiyonuİşle(_ aksiyon: ProfilAksiyonu) {
        // Profil aksiyonlarını işle
    }
}

enum SosyalRota: Hashable {
    case gönderiDetayı(Gönderi)
    case kullanıcıProfili(Kullanıcı)
    case yorumlar(Gönderi)
}

URL Tabanlı Navigasyon Uygulaması

struct DeepLinkNavigasyonGörünümü: View {
    @State private var navigasyonYolu = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigasyonYolu) {
            AnaGörünüm()
                .navigationDestination(for: DeepLinkHedefi.self) { hedef in
                    deepLinkHedefi(for: hedef)
                }
                .onOpenURL { url in
                    deepLinkİşle(url)
                }
        }
    }
    
    private func deepLinkİşle(_ url: URL) {
        guard let bileşenler = URLComponents(url: url, resolvingAgainstBaseURL: false),
              let host = bileşenler.host else { return }
        
        // Mevcut navigasyonu temizle
        navigasyonYolu = NavigationPath()
        
        switch host {
        case "kullanıcı":
            if let kullanıcıID = bileşenler.queryItems?.first(where: { $0.name == "id" })?.value {
                navigasyonYolu.append(DeepLinkHedefi.kullanıcı(kullanıcıID))
            }
        case "ürün":
            if let ürünIDString = bileşenler.queryItems?.first(where: { $0.name == "id" })?.value,
               let ürünID = Int(ürünIDString) {
                navigasyonYolu.append(DeepLinkHedefi.ürün(ürünID))
            }
        case "ayarlar":
            navigasyonYolu.append(DeepLinkHedefi.ayarlar)
        default:
            break
        }
    }
    
    @ViewBuilder
    private func deepLinkHedefi(for hedef: DeepLinkHedefi) -> some View {
        switch hedef {
        case .kullanıcı(let kullanıcıID):
            KullanıcıDetayGörünümü(kullanıcıID: kullanıcıID)
        case .ürün(let ürünID):
            ÜrünDetayGörünümü(ürünID: ürünID)
        case .ayarlar:
            AyarlarView()
        }
    }
}

enum DeepLinkHedefi: Hashable {
    case kullanıcı(String)
    case ürün(Int)
    case ayarlar
}

En İyi Uygulamalar ve Geçiş İpuçları

// Önce: NavigationView (Kullanımdan Kaldırıldı)
struct EskiNavigasyonGörünümü: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Ayarlar", destination: AyarlarView())
                NavigationLink("Profil", destination: ProfilView())
            }
            .navigationTitle("Ana Sayfa")
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

// Sonra: NavigationStack (Önerilen)
struct YeniNavigasyonGörünümü: View {
    @State private var navigasyonYolu = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigasyonYolu) {
            List {
                Button("Ayarlar") {
                    navigasyonYolu.append(Hedef.ayarlar)
                }
                Button("Profil") {
                    navigasyonYolu.append(Hedef.profil)
                }
            }
            .navigationTitle("Ana Sayfa")
            .navigationDestination(for: Hedef.self) { hedef in
                switch hedef {
                case .ayarlar:
                    AyarlarView()
                case .profil:
                    ProfilView()
                }
            }
        }
    }
}

enum Hedef: Hashable {
    case ayarlar
    case profil
}

Performans Optimizasyon İpuçları

struct OptimizeNavigasyonGörünümü: View {
    @State private var navigasyonYolu = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigasyonYolu) {
            İçerikGörünümü()
                .navigationDestination(for: OptimizeRota.self) { rota in
                    optimizeHedef(for: rota)
                }
        }
    }
    
    @ViewBuilder
    private func optimizeHedef(for rota: OptimizeRota) -> some View {
        switch rota {
        case .tembeleYüklenmiş(let id):
            TembeleYüklenmiş DetayGörünümü(id: id)
                .onAppear {
                    sonrakiGörünümüÖnYükle(for: id)
                }
        case .önbelleklenmişGörünüm(let veri):
            ÖnbelleklenmişİçerikGörünümü(veri: veri)
        }
    }
    
    private func sonrakiGörünümüÖnYükle(for id: String) {
        // Ön yükleme mantığını uygula
    }
}

enum OptimizeRota: Hashable {
    case tembeleYüklenmiş(String)
    case önbelleklenmişGörünüm(ÖnbelleklenmişVeri)
}

Sonuç

NavigationStack, SwiftUI navigasyon yeteneklerinde büyük bir sıçramayı temsil ediyor. Programatik kontrolü, tip güvenliği ve cihazlar arası tutarlı davranışı, modern iOS geliştirme için açık seçim yapıyor.

Önemli Çıkarımlar:

  1. Her zaman NavigationStack kullanın iOS 16+ hedefleyen yeni projeler için
  2. Uygun navigasyon durum yönetimi uygulayın karmaşık uygulamalar için
  3. Tip güvenli hedefler kullanın çalışma zamanı hatalarını önlemek için
  4. Deep linking stratejinizi planlayın geliştirmenin erken aşamasında
  5. Navigasyon akışlarını kapsamlı test edin farklı cihazlarda

Geçiş Zaman Çizelgesi:

NavigationStack sadece bir değişiklik değil—tamamen yeni kullanıcı etkileşim kalıplarını mümkün kılan güçlü bir araçtır. Ustalaşın ve doğal, duyarlı ve tamamen modern hissettiren navigasyona sahip uygulamalar oluşturun.


En son SwiftUI gelişmelerinden haberdar olmak mı istiyorsunuz? Haftalık ipuçları, eğitimler ve sektör içgörüleri için bültenimize abone olun.