09 May 2025·6 dk okuma

SwiftUI NavigationStack ile Öngörülebilir Çok Adımlı Akış Kalıpları

SwiftUI NavigationStack ile çok adımlı akışlar için açık yönlendirme, güvenli geri davranışı ve onboarding/onay sihirbazları için pratik örnekler.

SwiftUI NavigationStack ile Öngörülebilir Çok Adımlı Akış Kalıpları

Çok adımlı akışlarda neler yanlış gidebilir

Çok adımlı akış, adım 1'in gerçekleşmesi gerektiği ve ardından adım 2'nin anlam kazanacağı herhangi bir ardışık süreçtir. Yaygın örnekler onboarding, bir onay isteği (inceleme, onay, gönder) ve bir kişinin bir taslağı birden fazla ekranda oluşturduğu sihirbaz tarzı veri girişi akışlarıdır.

Bu akışlar yalnızca Geri, insanların beklediği şekilde davrandığında kolay hissedilir. Eğer Geri onları şaşırtacak bir yere götürürse, kullanıcılar uygulamaya güvenmeyi bırakır. Bu, yanlış gönderimler, yarıda bırakılmış onboarding ve "İmlediğim ekrana geri dönemiyorum" gibi destek talepleri şeklinde ortaya çıkar.

Dağınık gezinme genellikle şu şekillerde görünür:

  • Uygulama yanlış ekrana atlıyor veya akıştan çok erken çıkıyor.
  • Aynı ekran iki kez görünüyor çünkü iki kez push edildi.
  • Bir adım Geri ile sıfırlanıyor ve kullanıcı taslağını kaybediyor.
  • Kullanıcı adım 1'i tamamlamadan adım 3'e ulaşabiliyor, bu da geçersiz durum yaratıyor.
  • Derin bağlantı veya uygulama yeniden başlatıldıktan sonra doğru ekran gösteriliyor ama veriler yanlış.

Yararlı bir zihinsel model: çok adımlı akış, birlikte hareket eden iki şeydir.

İlki, kullanıcı geriye doğru gidebileceği ekranların bir yığınıdır. İkincisi, ekran kaybolsa bile yok olmaması gereken paylaşılan akış durumu (taslak veriler ve ilerleme).

Birçok NavigationStack kurulumu, ekran yığını ile akış durumu ayrıştığında bozulur. Örneğin, bir onboarding akışı "Profil oluştur"u iki kez push edebilir (çiftleşen rotalar) ve taslak profil view içinde canlı kaldığı için yeniden render edildiğinde yeniden oluşturulur. Kullanıcı Geri'ye basar, formun farklı bir sürümünü görür ve uygulamanın güvenilmez olduğunu düşünür.

Öngörülebilir davranış, akışa isim vermek, her adımda Geri'nin ne yapması gerektiğini tanımlamak ve akış durumuna tek, net bir yuva sağlamakla başlar.

Gerçekten ihtiyaç duyduğunuz NavigationStack temelleri

Çok adımlı akışlar için, daha eski NavigationView yerine NavigationStack kullanın. NavigationView iOS sürümleri arasında farklı davranabilir ve ekran push/pop veya geri yükleme yaparken mantık kurmak daha zordur. NavigationStack, gezinmeyi gerçek bir yığın gibi ele alan modern API'dir.

NavigationStack, kullanıcının nerede olduğunu gösteren bir geçmiş saklar. Her push yığına bir hedef ekler. Her geri işlemi bir hedefi pop eder. Bu basit kural, akışın stabil hissetmesini sağlar: UI net bir adımlar dizisini yansıtmalıdır.

Yığının gerçekte ne tuttuğu

SwiftUI view nesnelerinizi saklamaz. Gezinti için kullandığınız veriyi (route değerinizi) saklar ve gerektiğinde hedef görünümü yeniden oluşturmak için bunu kullanır. Bunun birkaç pratik sonucu vardır:

  • Önemli verileri tutmak için bir view'ın canlı kalacağına güvenmeyin.
  • Bir ekranın state'e ihtiyacı varsa, it dışarıda yaşayan bir modele (ör. ObservableObject) koyun.
  • Aynı hedefi farklı verilerle iki kez push ederseniz, SwiftUI bunları farklı yığın girdileri olarak değerlendirir.

NavigationPath, akışınız sadece bir veya iki sabit push'tan ibaret olmadığında elinize aldığınız şeydir. Bunu, düzenlenebilir "nereye gidiyoruz" değerleri listesi olarak düşünün. İleri gitmek için rotalar ekleyebilir, geri gitmek için son rotayı kaldırabilir veya daha ileri bir adıma atlamak için tüm path'i değiştirebilirsiniz.

Bu, sihirbaz tarzı adımlarda, akışı tamamladıktan sonra sıfırlamak gerektiğinde veya kaydedilmiş durumdan kısmi bir akışı geri yüklemek istediğinizde iyi bir uyum sağlar.

Öngörülebilir, zekice olandan daha iyidir. Daha az gizli kural (otomatik atlamalar, örtük pop'lar, view kaynaklı yan etkiler) ileride daha az garip geri yığın hatası demektir.

Akışı küçük bir route enum ile modelleyin

Öngörülebilir gezinme tek bir kararla başlar: yönlendirmeyi tek bir yerde tutun ve akıştaki her ekranı küçük, net bir değer yapın.

Tek bir bilgi kaynağı oluşturun, örneğin FlowRouter (bir ObservableObject) ve NavigationPath'a sahip olsun. Bu her push ve pop'u tutarlı tutar, view'lara yayılmış gezinmeyle karşılaştırıldığında daha güvenilirdir.

Basit bir router yapısı

Adımları temsil etmek için bir enum kullanın. İlişkilendirilmiş değerleri sadece hafif kimlikler (ör. ID'ler) için ekleyin, tüm modeller için değil.

enum Step: Hashable {
    case welcome
    case profile
    case verifyCode(phoneID: UUID)
    case review(applicationID: UUID)
    case done
}

final class FlowRouter: ObservableObject {
    @Published var path = NavigationPath()

    func go(_ step: Step) { path.append(step) }
    func back() { if !path.isEmpty { path.removeLast() } }
    func reset() { path = NavigationPath() }
}

Akış durumunu gezinme durumundan ayrı tutun

Gezinmeyi "kullanıcının nerede olduğu", akış durumunu ise "şimdiye kadar ne girdikleri" olarak ele alın. Akış verilerini kendi deposuna koyun (ör. name, email, yüklenen belgeler içeren OnboardingState) ve ekranlar gelip giderken bunu koruyun.

Basit bir kural:

  • FlowRouter.path yalnızca Step değerleri içerir.
  • OnboardingState kullanıcının girdilerini ve taslağını tutar.
  • Adımlar, verileri almak için ID taşır, verinin kendisini değil.

Bu, kırılgan hashing, devasa path'ler ve SwiftUI view'ları yeniden oluşturduğunda beklenmedik sıfırlamaların önüne geçer.

Adım adım: NavigationPath ile bir sihirbaz oluşturun

Sihirbaz tarzı ekranlar için en basit yaklaşım yığını kendiniz kontrol etmektir. "Şu anda nerede olduğumuz?" için tek bir doğru kaynak ve ileri/geri gitmek için tek bir yol olması hedeflensin.

NavigationStack(path:) ile NavigationPath'a bağlanarak başlayın. Her push edilmiş ekran bir değerle (çoğunlukla enum vakası) temsil edilir ve hedefleri bir kez kaydedin.

import SwiftUI

enum WizardRoute: Hashable {
    case profile
    case verifyEmail
    case permissions
    case review
}

struct OnboardingWizard: View {
    @State private var path = NavigationPath()
    @State private var currentIndex = 0

    private let steps: [WizardRoute] = [.profile, .verifyEmail, .permissions, .review]

    var body: some View {
        NavigationStack(path: $path) {
            StartScreen {
                goToStep(0) // push first step
            }
            .navigationDestination(for: WizardRoute.self) { route in
                switch route {
                case .profile:
                    ProfileStep(onNext: { goToStep(1) })
                case .verifyEmail:
                    VerifyEmailStep(onNext: { goToStep(2) })
                case .permissions:
                    PermissionsStep(onNext: { goToStep(3) })
                case .review:
                    ReviewStep(onEditProfile: { popToStep(0) })
                }
            }
        }
    }

    private func goToStep(_ index: Int) {
        currentIndex = index
        path.append(steps[index])
    }

    private func popToStep(_ index: Int) {
        let toRemove = max(0, currentIndex - index)
        if toRemove > 0 { path.removeLast(toRemove) }
        currentIndex = index
    }
}

Geri'yi öngörülebilir tutmak için birkaç alışkanlığa bağlı kalın. İlerlemenin her adımı için tam olarak bir rota ekleyin, "İleri"yi doğrusal tutun (yalnızca bir sonraki adımı push edin) ve geri atlama gerektiğinde (ör. İncelemeden "Profili düzenle") yığını bilinen bir indekse kırpın.

Bu, kazara tekrar eden ekranların önüne geçer ve Geri'nin kullanıcıların beklediği gibi olmasını sağlar: bir dokunuş bir adım demektir.

Ekranlar gelirken ve giderken veriyi kararlı tutun

Build predictable multi-step flows
Build wizard-style flows with clear steps and stable draft data, without hand-coded navigation.
Try Now

Her ekran kendi state'ine sahip olduğunda çok adımlı bir akış güvensiz hisseder. Bir isim yazarsınız, ileri gider, geri gelir ve alan boş çünkü view yeniden oluşturulmuştur.

Çözüm basittir: akışı tek bir taslak nesne olarak ele alın ve her adım bunun üzerinde düzenleme yapsın.

SwiftUI'de bu genellikle akışın başında bir kez oluşturulan ve her adımda paylaşılan bir ObservableObject kullanmak demektir. Eğer taslak değerleri gerçekten sadece o ekrana ait değilse, her view'ın @State'inde saklamayın.

final class OnboardingDraft: ObservableObject {
    @Published var fullName = ""
    @Published var email = ""
    @Published var wantsNotifications = false

    var canGoNextFromProfile: Bool {
        !fullName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        && email.contains("@")
    }
}

Bunu akış giriş noktasında oluşturun, sonra @StateObject ve @EnvironmentObject ile veya açıkça geçirerek paylaşın. Böylece yığın değişse bile veri kaybolmaz.

Geri navigasyon sırasında nelerin korunacağına karar verin

Her şey sonsuza dek korunmamalı. Kurallarınızı önceden belirleyin ki akış tutarlı kalsın.

Kullanıcı girdilerini (metin alanları, toggle'lar, seçimler) saklayın; yalnızca açıkça sıfırlanmadıkça korunmalı. Ekrana özgü UI durumlarını sıfırlayın (yükleniyor spinner'ları, geçici uyarılar, kısa animasyonlar). Hassas alanları (tek kullanımlık kodlar gibi) o ekrandan ayrılırken temizleyin. Bir seçim sonraki adımları etkiliyorsa, sadece bağımlı alanları temizleyin.

Doğrulama burada doğal bir yer bulur. Kullanıcıların ilerlemesine izin verip sonraki ekranda hata göstermek yerine, geçerli adım doğrulanana kadar kullanıcıyı o adımda tutun. canGoNextFromProfile gibi hesaplanmış bir özelliğe bağlı olarak düğmeyi devre dışı bırakmak genellikle yeterlidir.

Checkpoint'leri aşırıya kaçmadan kaydedin

Bazı taslaklar yalnızca bellekte yaşayabilir. Diğerleri uygulama yeniden başlatmalarına veya çökmesine dayanmalı. Pratik bir varsayılan:

  • Kullanıcı adımlarda aktif olarak ilerlerken veriyi bellekte tutun.
  • Net kilometre taşlarında (hesap oluşturuldu, onay gönderildi, ödeme başlatıldı) yerel olarak kalıcılaştırın.
  • Akış uzun veya veri girişi bir dakikadan fazla sürüyorsa daha erken kaydedin.

Bu şekilde ekranlar serbestçe gelip gidebilir ve kullanıcının ilerlemesi zamanına saygılı ve güvenli hisseder.

Derin bağlantılar ve kısmen bitmiş bir akışı geri yükleme

Gerçek akışlar nadiren adım 1'de başlar, bu yüzden derin bağlantılar önemlidir. Birisi e-postadaki bir bağlantıya, push bildirime veya paylaşılan bir linke tıklar ve onboarding'in 3. adımı veya son onay ekranı gibi doğru ekrana gelmeyi bekler.

NavigationStack ile derin bağlantıyı tek bir ekrana ışınlama komutu gibi değil, geçerli bir path oluşturma talimatı olarak ele alın. Akışın başından başlayın ve yalnızca bu kullanıcı ve oturum için geçerli adımları ekleyin.

Harici linki güvenli bir rota sırasına çevirme

İyi bir desen: dış ID'yi ayrıştırın, ihtiyacınız olan minimum veriyi yükleyin, sonra bunu bir rota dizisine dönüştürün.

enum Route: Hashable {
    case start
    case profile
    case verifyEmail
    case approve(requestID: String)
}

func pathForDeepLink(requestID: String, hasProfile: Bool, emailVerified: Bool) -> [Route] {
    var routes: [Route] = [.start]
    if !hasProfile { routes.append(.profile) }
    if !emailVerified { routes.append(.verifyEmail) }
    routes.append(.approve(requestID: requestID))
    return routes
}

Bu kontroller sizin emniyet bariyerinizdir. Önkoşullar eksikse, kullanıcıyı hata ile adım 3'e bırakmayın; eksik ilk adıma gönderin ve geri yığının hâlâ tutarlı bir hikaye anlattığından emin olun.

Kısmen bitmiş bir akışı geri yükleme

Yeniden başlatmadan sonra geri yüklemek için iki şeyi kaydedin: son bilinen rota durumu ve kullanıcı tarafından girilmiş taslak veriler. Sonra insanları şaşırtmadan nasıl devam edeceğinize karar verin.

Eğer taslak taze ise (dakikalar veya saatler içinde), açık bir "Devam Et" seçeneği sunun. Eskiyse, alanları ön doldurmak için taslağı tutarak akışı baştan başlatmak genellikle kullanıcıyı ortada bırakmaktan daha az şaşırtıcıdır. Gereksinimler değiştiyse, aynı guardrail'leri kullanarak path'i yeniden oluşturun.

Push vs modal: akışı kolayca kapatılabilir tutun

Put these patterns into practice
Build the same kind of reliable multi-step experiences discussed here using a no-code platform.
Try AppMaster

Bir akış, ileriye doğru tek ana yol olduğunda öngörülebilir hisseder: ekranları tek bir yığında push etmek. Yan görevler için sheet ve full-screen cover kullanın, ana yol için değil.

Push (NavigationStack), kullanıcının Geri ile adımları geri takip etmesini beklediği durumlara uyar. Modaller (sheet veya fullScreenCover) kullanıcı yan bir görev yaparken, hızlı bir seçim yaparken veya riskli bir işlemi onaylarken uygundur.

Basit bir kural seti çoğu gezinme tuhaflığını önler:

  • Ana yol için push kullanın (Adım 1, Adım 2, Adım 3).
  • Küçük isteğe bağlı görevler için sheet kullanın (tarih seç, ülke seç, belge tarama).
  • "Ayrı dünyalar" için fullScreenCover kullanın (giriş, kamera yakalama, uzun yasal belge).
  • Onaylar için modal kullanın (akışı iptal et, taslağı sil, onay için gönder).

Yaygın hata, ana akış ekranlarını sheet içine koymaktır. Eğer Adım 2 bir sheet ise, kullanıcı onu kaydırarak kapatabilir, bağlamı kaybedebilir ve yığın Adım 1'deyken veriler Adım 2'nin tamamlandığını söyleyebilir.

Onaylar tersidir: "Emin misin?" ekranını sihirbaza push etmek yığını karıştırır ve döngüler yaratabilir (Step 3 -> Confirm -> Back -> Step 3 -> Back -> Confirm).

“Bitti” sonrası her şeyi temiz kapatma

"Bitti"nın ne anlama geldiğine önce karar verin: ana ekrana dönmek mi, listeye dönmek mi yoksa başarı ekranı göstermek mi?

Eğer akış push ile ilerlediyse, NavigationPath'i boşaltarak başlangıca dönün. Akış modal olarak sunulduysa, environment'tan dismiss() çağırın. Hem modal hem NavigationStack varsa, modalı kapatın, her push edilmiş ekranı tek tek kapatmayın. Başarılı gönderiden sonra taslağı temizleyin ki yeniden açılan akış temiz başlasın.

Geri düğmesi davranışı ve “Emin misiniz?” anları

Add essentials to your flow
Use pre-built modules like auth and payments to complete end-to-end flows faster.
Explore Platform

Çoğu çok adımlı akış için en iyi hareket hiçbir şey yapmamaktır: sistem back düğmesine (ve kaydırarak geri jestine) izin verin. Bu kullanıcı beklentisiyle eşleşir ve UI bir şeyi söylerken gezinme durumunun farklı olduğu hatalarını önler.

Geri'yi yalnızca geri gitmek gerçek zarar verecekse engelleyin; örneğin uzun, kaydedilmemiş bir formu kaybetme gibi. Eğer kullanıcı güvenle dönebiliyorsa ve devam edebiliyorsa sürtüşme eklemeyin.

Pratik bir yaklaşım: sistem gezinmesini koruyun ama ekran "dirty" (düzenlenmiş) ise sadece o zaman onay ekleyin. Bu, kendi geri eyleminizi sağlayıp bir kez sorup açık bir çıkış yolu sunmak demektir.

@Environment(\.dismiss) private var dismiss
@State private var showLeaveConfirm = false
let hasUnsavedChanges: Bool

var body: some View {
  Form { /* fields */ }
    .navigationBarBackButtonHidden(hasUnsavedChanges)
    .toolbar {
      if hasUnsavedChanges {
        ToolbarItem(placement: .navigationBarLeading) {
          Button("Back") { showLeaveConfirm = true }
        }
      }
    }
    .confirmationDialog("Discard changes?", isPresented: $showLeaveConfirm) {
      Button("Discard", role: .destructive) { dismiss() }
      Button("Keep Editing", role: .cancel) {}
    }
}

Bunu bir tuzağa dönüştürmemeye dikkat edin:

  • Sadece sonucu bir cümleyle açıklayabildiğinizde sorun.
  • Güvenli bir seçenek (İptal, Düzenlemeye Devam) ve net bir çıkış (Sil, Ayrıl) sunun.
  • Geri düğmelerini gizlemeyin; gizliyorsanız bunun yerine belirgin bir Geri veya Kapat butonu koyun.
  • Her yerde gezinmeyi engellemek yerine geri dönüşü olmayan işlemi (ör. "Onayla") onaylamayı tercih edin.

Geri jestiyle sık sık mücadele ediyorsanız, bu genellikle akışın otomatik kayda, kaydedilmiş taslağa veya daha küçük adımlara ihtiyacı olduğunun işaretidir.

Garip geri yığınları yaratan yaygın hatalar

Çoğu "neden oraya geri gitti?" hatası SwiftUI'nin rastgele davranmasından değil, gezinme durumunu kararsız hale getiren kalıplardan kaynaklanır. Öngörülebilir davranış için geri yığınını uygulama verisi gibi ele alın: stabil, test edilebilir ve tek bir yer tarafından sahiplenilmiş.

Kazara ekstra yığınlar

Yaygın bir tuzak farkında olmadan birden fazla NavigationStack ile sonuçlanmaktır. Örneğin, her sekmenin kendi root yığını vardır ve sonra bir child view akış içinde başka bir stack ekler. Sonuç kafa karıştırıcı geri davranışı, eksik navigation bar'ları veya ekranların beklediğiniz gibi pop olmamasıdır.

Başka bir sık sorun NavigationPath'i çok sık yeniden oluşturmak. Eğer path bir view içinde oluşturuluyorsa ve view re-render oluyorsa, state değişiklikleri sırasında sıfırlanabilir ve kullanıcı bir alana yazarken onları Step 1'e atlayabilir.

Çoğu garip yığının ardındaki hatalar basittir:

  • Bir NavigationStack içinde başka bir NavigationStack iç içe geçirmek (çoğunlukla sekmeler veya sheet içeriğinde)
  • Görünüm güncellemeleri sırasında NavigationPath()'i yeniden başlatmak yerine onu uzun ömürlü state içinde tutmamak
  • Rotaya kararsız değerler koymak (değişen bir model gibi), bu da Hashable'ı bozar ve hedeflerin uyumsuz olmasına neden olur
  • Gezinme kararlarını düğme handler'larına yaymak; böylece kimse "ileri"nin ne olduğunu açıklayamaz
  • Akışı aynı anda birden fazla kaynaktan sürmek (örneğin hem view model hem view path'i değiştirmeye çalışır)

Adımlar arasında veri geçirmeniz gerekiyorsa, rotada stabil kimlikleri (ID'ler, step enum'ları) tercih edin ve gerçek form verisini paylaşılan state'te tutun.

Somut bir örnek: route'nuz .profile(User) ise ve User kişi yazdıkça değişiyorsa, SwiftUI bunu farklı bir rota olarak görebilir ve yığını yeniden yapılandırabilir. Route'u .profile yapın ve taslak profili paylaşılan state'te saklayın.

Öngörülebilir gezinme için hızlı kontrol listesi

Test Back behavior early
Prototype the full flow quickly, then refine screens without breaking the user journey.
Prototype Now

Bir akış ters hissettirdiğinde, genellikle geri yığını kullanıcının anlattığı hikayeyle aynı şeyi söylemiyordur. UI'yı parlatmadan önce gezinme kurallarınızı gözden geçirin.

Gerçek bir cihazda test edin, sadece önizlemelerde değil, ve hem yavaş hem hızlı dokunuşları deneyin. Hızlı dokunuşlar genellikle çift push ve eksik state hatalarını ortaya çıkarır.

  • Son ekrandan ilk ekrana kadar bir adım geriye gidin. Her ekran kullanıcının önce girdiği aynı verileri gösteriyor mu kontrol edin.
  • Her adımda (ilk ve son dahil) İptal tetikleyin. Her zaman mantıklı bir yere mi döndüğünü doğrulayın, rastgele bir önceki ekrana değil.
  • Akışın ortasında zorla uygulamayı kapatıp yeniden başlatın. Güvenli bir şekilde devam edebildiğinizden emin olun; ya path'i geri yükleyerek ya da kaydedilmiş verilerle bilinen bir adımdan yeniden başlatarak.
  • Akışı bir derin bağlantı veya uygulama kısayolu ile açın. Hedef adımın geçerli olduğunu doğrulayın; eğer gerekli veri eksikse, en erken veriyi toplayabilecek adımı gösterin.
  • Bitti ile tamamlayın ve akışın temizce kaldırıldığını doğrulayın. Kullanıcı tamamlanmış bir sihirbazı tekrar Geri ile yeniden girmemeli.

Test için basit bir yol: üç ekranlı bir onboarding sihirbazı hayal edin (Profil, İzinler, Onay). Bir isim girin, ilerleyin, geri gelin, düzenleyin, sonra bir derin bağlantıyla doğrudan Onay'a atlayın. Eğer Onay eski adı gösteriyor veya Geri sizi çiftlenmiş bir Profil ekranına götürüyorsa, path güncellemeleriniz tutarlı değil demektir.

Kontrol listesini sürpriz olmadan geçebiliyorsanız, kullanıcılar akışı terk edip geri döndüklerinde bile süreç sakin ve öngörülebilir hissedecektir.

Gerçekçi bir örnek ve sonraki adımlar

Bir gider isteği için yönetici onay akışını düşünün. Dört adımı var: İncele, Düzenle, Onayla ve Makbuz. Kullanıcı bir şeyi bekler: Geri her zaman önceki adıma gider, önce ziyaret ettiği rastgele bir ekrana değil.

Basit bir route enum bunu öngörülebilir tutar. NavigationPath yalnızca route ve durumu yeniden yüklemek için gereken küçük kimlikleri (ör. expenseID ve mode — inceleme vs düzenleme) saklamalıdır. Büyük, değişken modelleri path'e push etmekten kaçının; bu, geri yüklemeleri ve derin bağlantıları kırılgan hale getirir.

Çalışma taslağını view'ların dışında tek bir doğruluk kaynağında tutun, örneğin bir @StateObject akış modeli (veya bir store). Her adım bu modeli okur ve yazar, böylece ekranlar görünüp kaybolsa da girdiler kaybolmaz.

En azından üç şeyi takip ediyorsunuz:

  • Rotalar (ör. review(expenseID), edit(expenseID), confirm(expenseID), receipt(expenseID))
  • Veri (satır kalemleri ve notlar içeren bir taslak obje ve pending, approved, rejected gibi bir durum)
  • Konum (akış modelinizdeki taslak, sunucudaki kanonik kayıt ve yerel küçük bir restore token: expenseID + son adım)

Kenar durumları akışların güven kazanıp kaybettiği yerlerdir. Yönetici Confirm'da reddederse, Geri'nin Düzenle'ye mi döneceğine yoksa akıştan mı çıkacağına karar verin. Sonra geri dönerlerse, kaydedilmiş token'dan son adımı geri yükleyin ve taslağı yeniden yükleyin. Cihaz değiştirirlerse, sunucuyu gerçek olarak kabul edin: yığına sunucu durumuna göre yeniden inşa edin ve onları doğru adıma gönderin.

Sonraki adımlar: route enum'unuzu belgeleyin (her case ne anlama geliyor ve ne zaman kullanılıyor), path oluşturma ve restore davranışı için birkaç temel test ekleyin ve bir kural koyun: view'lar gezinme kararlarına sahip olmasın.

Eğer aynı tür çok adımlı akışları sıfırdan yazmadan oluşturuyorsanız, AppMaster (appmaster.io) gibi platformlar aynı ayrımı uygular: adım navigasyonu ve iş verilerini ayrı tutun ki ekranlar değişse bile kullanıcının ilerlemesi bozulmasın.

SSS

Çok adımlı bir SwiftUI akışında Geri düğmesini nasıl öngörülebilir tutarım?

Use NavigationStack with a single NavigationPath you control. Push exactly one route per “Next” action and pop exactly one route per Back action. When you need a jump (like “Edit profile” from Review), trim the path to a known step instead of pushing more screens.

Form verilerim geri giderken neden kayboluyor?

Because SwiftUI rebuilds destination views from the route value, not from a preserved view instance. If your form data lives in the view’s @State, it can reset when the view is recreated. Put draft data in a shared model (like an ObservableObject) that lives outside the pushed views.

Yığın içinde aynı ekranı neden iki kez görüyorum?

It usually happens when you append the same route more than once (often due to fast taps or multiple code paths triggering navigation). Disable the Next button while you’re navigating or while validation/loading runs, and keep navigation mutations in one place so only one append happens per step.

Route enum'uma ne koymalıyım, neyi dışarıda tutmalıyım?

Keep routing values small and stable, like an enum case plus lightweight IDs. Store mutable data (the draft) in a separate shared object and look it up by ID if needed. Pushing large, changing models into the path can break Hashable expectations and cause mismatched destinations.

Gezinme durumunu ve akış durumunu nasıl temiz bir şekilde ayırırım?

Navigation is “where the user is,” and flow state is “what they’ve entered.” Own the navigation path in a router (or one top-level state) and own the draft in a separate ObservableObject. Each screen edits the draft; the router only changes steps.

Bir sihirbazın 3. adımına giden derin bağlantıları en güvenli şekilde nasıl ele alırım?

Treat a deep link as instructions to build a valid sequence of steps, not a teleport to one screen. Build the path by appending required prerequisite steps first (based on what the user has completed), then append the target step. This keeps the back stack coherent and avoids invalid state.

Uygulama yeniden başlatıldıktan sonra kısmen bitmiş bir akışı nasıl geri yüklerim?

Save two things: the last meaningful route (or step identifier) and the draft data. On relaunch, rebuild the path using the same prerequisite checks you use for deep links, then load the draft. If the draft is old, restarting the flow but prefilling fields is often less surprising than dropping the user mid-wizard.

Çok adımlı bir akışta ne zaman push, ne zaman modal kullanmalıyım?

Push screens for the main step-by-step path so Back retraces the flow naturally. Use sheets for optional side tasks and fullScreenCover for separate experiences like login or camera capture. Avoid putting core steps in modals because dismiss gestures can desync the UI from the flow state.

Geri jestini override edip “Emin misiniz?” diyerek onay göstermeli miyim?

Don’t intercept Back by default; let the system behavior work. Add a confirmation only when leaving would lose meaningful unsaved work, and only when the screen is actually “dirty.” Prefer autosave or draft persistence when you find yourself needing confirmations frequently.

Garip back stack hatalarına en sık hangi hatalar sebep olur?

Common causes are nesting multiple NavigationStacks, recreating NavigationPath during view updates, and having multiple owners mutate the path. Keep one stack per flow, keep the path in long-lived state (@StateObject or a single router), and centralize all push/pop logic to one place.

Başlaması kolay
Harika bir şey yaratın

Ücretsiz planla AppMaster ile denemeler yapın.
Hazır olduğunuzda uygun aboneliği seçebilirsiniz.

Başlayın