09 Mei 2025·6 menit membaca

Pola NavigationStack SwiftUI untuk alur multi-langkah yang dapat diprediksi

Pola NavigationStack SwiftUI untuk alur multi-langkah: routing yang jelas, perilaku Kembali yang aman, dan contoh praktis untuk onboarding serta wizard persetujuan.

Pola NavigationStack SwiftUI untuk alur multi-langkah yang dapat diprediksi

Apa yang salah dalam alur multi-langkah

Alur multi-langkah adalah setiap rangkaian di mana langkah 1 harus terjadi sebelum langkah 2 masuk akal. Contoh umum termasuk onboarding, permintaan persetujuan (review, konfirmasi, kirim), dan pengisian formulir bergaya wizard di mana seseorang membangun draft di beberapa layar.

Alur ini terasa mudah hanya ketika Kembali berperilaku seperti yang diharapkan pengguna. Jika Kembali membawa mereka ke tempat yang mengejutkan, pengguna berhenti mempercayai aplikasi. Itu muncul sebagai pengajuan yang salah, onboarding yang ditinggalkan, dan tiket dukungan seperti, “Saya tidak bisa kembali ke layar tempat saya tadi.”

Navigasi yang berantakan biasanya terlihat seperti salah satu ini:

  • Aplikasi melompat ke layar yang salah, atau keluar dari alur terlalu cepat.
  • Layar yang sama muncul dua kali karena dipush dua kali.
  • Sebuah langkah mengatur ulang saat menekan Kembali dan pengguna kehilangan draft mereka.
  • Pengguna bisa mencapai langkah 3 tanpa menyelesaikan langkah 1, menciptakan state tidak valid.
  • Setelah deep link atau restart aplikasi, aplikasi menampilkan layar yang benar tetapi dengan data yang salah.

Model mental yang berguna: alur multi-langkah adalah dua hal yang bergerak bersama.

Pertama, tumpukan layar (apa yang bisa pengguna telusuri kembali). Kedua, state alur bersama (data draft dan progres yang tidak boleh hilang hanya karena sebuah layar menghilang).

Banyak setup NavigationStack berantakan saat stack layar dan state alur menjauh. Misalnya, alur onboarding mungkin mempush “Buat profil” dua kali (route duplikat), sementara draft profil hidup di dalam view dan dibuat ulang saat re-render. Pengguna menekan Kembali, melihat versi form yang berbeda, dan menganggap aplikasi tidak dapat diandalkan.

Perilaku yang dapat diprediksi dimulai dengan memberi nama alur, mendefinisikan apa yang seharusnya dilakukan Back pada setiap langkah, dan memberi state alur satu rumah yang jelas.

Dasar NavigationStack yang benar-benar Anda butuhkan

Untuk alur multi-langkah, gunakan NavigationStack daripada NavigationView yang lebih lama. NavigationView bisa berperilaku berbeda antar versi iOS dan lebih sulit untuk dipikirkan saat Anda push, pop, atau merestore layar. NavigationStack adalah API modern yang memperlakukan navigasi seperti stack nyata.

NavigationStack menyimpan riwayat di mana pengguna pernah berada. Setiap push menambahkan destination ke stack. Setiap aksi kembali mem-popping satu destination. Aturan sederhana itulah yang membuat alur terasa stabil: UI harus mencerminkan urutan langkah yang jelas.

Apa yang sebenarnya disimpan stack

SwiftUI tidak menyimpan objek view Anda. Ia menyimpan data yang Anda gunakan untuk menavigasi (nilai route Anda) dan menggunakannya untuk membangun ulang destination view saat diperlukan. Itu memiliki beberapa konsekuensi praktis:

  • Jangan mengandalkan view tetap hidup untuk menyimpan data penting.
  • Jika sebuah layar membutuhkan state, letakkan di model (seperti ObservableObject) yang hidup di luar view yang dipush.
  • Jika Anda mempush destination yang sama dua kali dengan data berbeda, SwiftUI menganggapnya sebagai entri stack yang berbeda.

NavigationPath adalah yang Anda gunakan ketika alur Anda bukan hanya satu atau dua push tetap. Anggaplah itu sebagai daftar yang dapat diedit dari nilai “ke mana kita akan pergi”. Anda bisa menambahkan route untuk maju, menghapus terakhir untuk kembali, atau mengganti seluruh path untuk melompat ke langkah selanjutnya.

Cocok ketika Anda membutuhkan langkah bergaya wizard, perlu mereset alur setelah selesai, atau ingin merestore alur parsial dari state yang disimpan.

Yang dapat diprediksi lebih baik daripada yang “pintar”. Semakin sedikit aturan tersembunyi (lompatan otomatis, pop implisit, efek samping yang digerakkan view) berarti semakin sedikit bug back stack aneh nanti.

Modelkan alur dengan enum route kecil

Navigasi yang dapat diprediksi dimulai dengan satu keputusan: pusatkan routing di satu tempat, dan buat setiap layar dalam alur menjadi nilai kecil dan jelas.

Buat satu sumber kebenaran, misalnya FlowRouter (sebuah ObservableObject) yang memiliki NavigationPath. Itu menjaga setiap push dan pop konsisten, daripada menyebarkan navigasi ke seluruh view.

Struktur router sederhana

Gunakan enum untuk merepresentasikan langkah. Tambahkan associated value hanya untuk pengenal ringan (seperti ID), bukan model penuh.

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() }
}

Jaga state alur terpisah dari state navigasi

Perlakukan navigasi sebagai “di mana pengguna berada,” dan state alur sebagai “apa yang telah mereka masukkan sejauh ini.” Letakkan data alur di store sendiri (mis. OnboardingState dengan nama, email, dokumen yang diunggah) dan jaga agar tetap stabil saat layar datang dan pergi.

Aturan praktis singkat:

  • FlowRouter.path hanya berisi nilai Step.
  • OnboardingState berisi input dan data draft pengguna.
  • Steps membawa ID untuk melihat data, bukan data itu sendiri.

Ini menghindari hashing yang rapuh, path besar, dan reset mengejutkan saat SwiftUI membangun ulang view.

Langkah demi langkah: bangun wizard dengan NavigationPath

Untuk layar bergaya wizard, pendekatan paling sederhana adalah mengendalikan stack sendiri. Tujuannya satu sumber kebenaran untuk “di mana saya dalam alur?” dan satu cara untuk maju atau mundur.

Mulai dengan NavigationStack(path:) yang terikat ke NavigationPath. Setiap layar yang dipush direpresentasikan oleh sebuah nilai (sering kali kasus enum), dan daftarkan destinasi sekali.

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
    }
}

Untuk menjaga Back tetap dapat diprediksi, patuhi beberapa kebiasaan. Tambahkan tepat satu route untuk maju, biarkan “Next” linear (hanya push langkah berikutnya), dan saat perlu melompat mundur (mis. “Edit profil” dari Review), potong stack ke indeks yang diketahui.

Ini menghindari layar duplikat tidak sengaja dan membuat Back sesuai harapan pengguna: satu ketukan sama dengan satu langkah.

Jaga data tetap stabil saat layar datang dan pergi

Dari alur ke produksi
Deploy aplikasi saat siap, baik ke penyedia cloud maupun lingkungan Anda sendiri.
Deploy Aplikasi

Alur multi-langkah terasa tidak andal ketika setiap layar memiliki state-nya sendiri. Anda mengetik nama, maju, kembali, dan field kosong karena view dibuat ulang.

Perbaikannya sederhana: perlakukan alur sebagai satu objek draft, dan biarkan setiap langkah mengeditnya.

Di SwiftUI, itu biasanya berarti ObservableObject bersama dibuat sekali di awal alur dan dibagikan ke setiap langkah. Jangan simpan nilai draft di @State setiap view kecuali memang milik layar itu saja.

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

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

Buat ini di titik masuk, lalu bagikan dengan @StateObject dan @EnvironmentObject (atau lewat parameter). Sekarang stack bisa berubah tanpa kehilangan data.

Tentukan apa yang bertahan saat navigasi mundur

Tidak semua hal harus bertahan selamanya. Tentukan aturan Anda di awal supaya alur tetap konsisten.

Pertahankan input pengguna (field teks, toggle, pilihan) kecuali mereka secara eksplisit direset. Reset state UI spesifik langkah (loading spinner, alert sementara, animasi singkat). Kosongkan field sensitif (seperti kode sekali pakai) saat meninggalkan langkah itu. Jika sebuah pilihan mengubah langkah berikutnya, bersihkan hanya field yang bergantung.

Validasi cocok di sini. Daripada membiarkan pengguna maju lalu menampilkan error di layar berikutnya, tahan mereka di langkah saat ini sampai valid. Menonaktifkan tombol berdasarkan properti terhitung seperti canGoNextFromProfile seringkali sudah cukup.

Simpan checkpoint tanpa berlebihan

Beberapa draft hanya bisa hidup di memori. Lainnya harus bertahan restart atau crash aplikasi. Default praktis:

  • Simpan data di memori saat pengguna aktif bergerak melalui langkah.
  • Persist secara lokal pada milestone yang jelas (akun dibuat, persetujuan dikirim, pembayaran dimulai).
  • Persist lebih awal jika alur panjang atau pengisian data memakan waktu lebih dari satu menit.

Dengan begitu, layar bisa datang dan pergi dengan bebas, dan progres pengguna masih terasa stabil serta menghargai waktu mereka.

Deep link penting karena alur nyata jarang dimulai di langkah 1. Seseorang mengetuk email, notifikasi push, atau link yang dibagikan dan berharap mendarat di layar yang tepat, seperti langkah 3 onboarding atau layar persetujuan akhir.

Dengan NavigationStack, perlakukan deep link sebagai instruksi untuk membangun path yang valid, bukan perintah untuk melompat ke satu view. Mulai dari awal alur dan tambahkan hanya langkah yang benar untuk pengguna dan sesi ini.

Polanya: parse ID eksternal, muat data minimal yang diperlukan, lalu konversi menjadi urutan route.

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
}

Pemeriksaan itu adalah pagar pengaman Anda. Jika prasyarat hilang, jangan menjatuhkan pengguna ke langkah 3 dengan error dan tanpa jalan maju. Kirim mereka ke langkah pertama yang hilang, dan pastikan back stack masih menceritakan sebuah alur yang koheren.

Merestore alur yang belum selesai

Untuk merestore setelah relaunch, simpan dua hal: state route terakhir yang diketahui dan data draft yang dimasukkan pengguna. Lalu putuskan bagaimana melanjutkan tanpa mengejutkan orang.

Jika draft masih segar (menit atau jam), tawarkan pilihan “Lanjutkan” yang jelas. Jika sudah lama, mulai dari awal tapi isi field dari draft. Jika persyaratan berubah, bangun kembali path menggunakan pagar pengaman yang sama.

Push vs modal: jaga alur mudah untuk keluar

Berikan data draft tempatnya
Modelkan data alur Anda di perancang basis data visual dan jaga konsistensinya antar langkah.
Buat Aplikasi

Alur terasa dapat diprediksi ketika ada satu cara utama untuk maju: mempush layar di satu stack. Gunakan sheet dan full-screen cover untuk tugas samping, bukan jalur utama.

Push cocok saat pengguna mengharapkan Kembali menelusuri langkah mereka. Modal (sheet atau fullScreenCover) cocok saat pengguna melakukan tugas samping, membuat pilihan cepat, atau mengonfirmasi aksi berisiko.

Aturan sederhana untuk mencegah anomali navigasi:

  • Push untuk jalur utama (Langkah 1, Langkah 2, Langkah 3).
  • Gunakan sheet untuk tugas kecil opsional (pilih tanggal, pilih negara, scan dokumen).
  • Gunakan fullScreenCover untuk “dunia terpisah” (login, capture kamera, dokumen hukum panjang).
  • Gunakan modal untuk konfirmasi (batal alur, hapus draft, kirim untuk persetujuan).

Kesalahan umum adalah memasukkan layar jalur utama ke dalam sheet. Jika Langkah 2 adalah sheet, pengguna bisa menggesek untuk menutupnya, kehilangan konteks, dan berakhir dengan stack yang mengatakan mereka di Langkah 1 sementara data menunjukkan mereka menyelesaikan Langkah 2.

Konfirmasi adalah kebalikan: mempush layar “Anda yakin?” ke dalam wizard mengacaukan stack dan dapat menciptakan loop (Langkah 3 -> Konfirmasi -> Kembali -> Langkah 3 -> Kembali -> Konfirmasi).

Cara menutup semuanya dengan rapi setelah “Selesai”

Tentukan dulu apa arti “Selesai”: kembali ke home, kembali ke daftar, atau menampilkan layar sukses.

Jika alur dipush, reset NavigationPath untuk mempop kembali ke awal. Jika alur dipresentasikan modal, panggil dismiss() dari environment. Jika Anda memiliki keduanya (modal yang berisi NavigationStack), dismiss modal, bukan setiap layar yang dipush. Setelah submit sukses, juga bersihkan state draft sehingga alur yang dibuka ulang dimulai bersih.

Perilaku tombol Kembali dan momen “Anda yakin?”

Kuasi basis kode aplikasi Anda
Pertahankan kontrol dengan mengekspor kode sumber nyata saat Anda butuh self-hosting atau kustomisasi.
Ekspor Kode

Untuk sebagian besar alur multi-langkah, pilihan terbaik adalah tidak melakukan apa-apa: biarkan tombol sistem bekerja. Ini sesuai ekspektasi pengguna dan menghindari bug di mana UI mengatakan satu hal tapi state navigasi mengatakan hal lain.

Intersepsi hanya layak saat kembali akan menyebabkan kerugian nyata, seperti kehilangan formulir panjang yang belum disimpan atau meninggalkan aksi yang tidak dapat dibatalkan. Jika pengguna bisa kembali dengan aman dan melanjutkan, jangan tambahkan hambatan.

Pendekatan praktis: pertahankan navigasi sistem, tapi tambahkan konfirmasi hanya saat layar “kotor” (edited). Itu berarti menyediakan aksi back sendiri dan menanyakan sekali, dengan jalan keluar yang jelas.

@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) {}
    }
}

Jangan biarkan ini berubah menjadi jebakan:

  • Tanyakan hanya ketika Anda bisa menjelaskan konsekuensinya dalam satu kalimat singkat.
  • Tawarkan opsi aman (Cancel, Keep Editing) plus keluaran yang jelas (Discard, Leave).
  • Jangan sembunyikan tombol kembali kecuali Anda menggantinya dengan Back atau Close yang jelas.
  • Lebih suka mengonfirmasi aksi yang tidak dapat dibatalkan (seperti “Approve”) daripada memblokir navigasi di mana-mana.

Jika Anda sering berjuang melawan gesture kembali, itu biasanya tanda alur perlu autosave, draft tersimpan, atau langkah yang lebih kecil.

Kesalahan umum yang menciptakan back stack aneh

Kebanyakan bug “mengapa kembali ke situ?” bukan SwiftUI yang acak. Mereka biasanya berasal dari pola yang membuat navigation state tidak stabil. Untuk perilaku yang dapat diprediksi, perlakukan back stack seperti data aplikasi: stabil, dapat dites, dan dimiliki oleh satu tempat.

Stack ekstra tidak sengaja

Perangkap umum adalah berakhir dengan lebih dari satu NavigationStack tanpa menyadarinya. Misalnya, setiap tab memiliki root stack sendiri, lalu view anak menambahkan stack lain di dalam alur. Hasilnya adalah perilaku back yang membingungkan, bar navigasi yang hilang, atau layar yang tidak mempop seperti yang Anda harapkan.

Masalah sering lain adalah membuat ulang NavigationPath terlalu sering. Jika path dibuat di dalam view yang re-render, ia bisa reset saat perubahan state dan melompatkan pengguna kembali ke langkah 1 setelah mereka mengetik di field.

Kesalahan yang menyebabkan sebagian besar stack aneh cukup sederhana:

  • Menempatkan NavigationStack di dalam stack lain (sering di dalam tab atau konten sheet)
  • Menginisialisasi ulang NavigationPath() saat update view alih-alih menyimpannya di state yang tahan lama
  • Menaruh nilai yang tidak stabil di route (seperti model yang berubah), yang merusak Hashable dan menyebabkan destination mismatch
  • Menyebarkan keputusan navigasi ke berbagai handler tombol sampai tak ada yang bisa menjelaskan apa arti “next”
  • Menggerakkan alur dari beberapa sumber sekaligus (mis. view model dan view yang memutasi path)

Jika Anda perlu melewatkan data antar langkah, gunakan ID yang stabil di route (ID, enum langkah) dan simpan data formulir yang sebenarnya di state bersama.

Contoh konkret: jika route Anda .profile(User) dan User berubah saat orang mengetik, SwiftUI bisa menganggapnya route berbeda dan merombak stack. Buat route .profile dan simpan data draft profil di state bersama.

Daftar periksa cepat untuk navigasi yang dapat diprediksi

Sentralisasikan logika alur secara visual
Ubah aturan bisnis kompleks menjadi proses drag-and-drop daripada handler tombol yang tersebar.
Mulai

Saat sebuah alur terasa tidak pas, biasanya karena back stack tidak menceritakan kisah yang sama dengan pengguna. Sebelum menghaluskan UI, lakukan pemeriksaan singkat atas aturan navigasi Anda.

Uji di perangkat nyata, bukan hanya preview, dan coba ketukan lambat serta cepat. Ketukan cepat sering mengungkap append ganda dan state yang hilang.

  • Kembali satu langkah pada satu waktu dari layar terakhir ke yang pertama. Konfirmasi setiap layar menampilkan data yang sama yang dimasukkan pengguna sebelumnya.
  • Trigger Cancel dari setiap langkah (termasuk pertama dan terakhir). Pastikan selalu kembali ke tempat yang masuk akal, bukan layar acak sebelumnya.
  • Force quit di tengah alur dan relaunch. Pastikan Anda bisa melanjutkan dengan aman, baik dengan merestore path atau memulai ulang di langkah yang diketahui dengan data yang tersimpan.
  • Buka alur menggunakan deep link atau shortcut aplikasi. Verifikasi langkah tujuan valid; jika data yang diperlukan hilang, arahkan ke langkah paling awal yang bisa mengumpulkannya.
  • Selesaikan dengan Done dan konfirmasi alur terhapus dengan rapi. Pengguna seharusnya tidak bisa menekan Kembali dan masuk kembali ke wizard yang telah selesai.

Cara cepat mengetes: bayangkan wizard onboarding dengan tiga layar (Profile, Permissions, Confirm). Masukkan nama, maju, kembali, edit, lalu lompat ke Confirm lewat deep link. Jika Confirm menampilkan nama lama, atau jika Back membawa Anda ke layar Profile duplikat, pembaruan path Anda tidak konsisten.

Jika Anda bisa lulus daftar periksa tanpa kejutan, alur Anda akan terasa tenang dan dapat diprediksi, bahkan ketika pengguna meninggalkan dan kembali nanti.

Contoh realistis dan langkah selanjutnya

Bayangkan alur persetujuan manajer untuk permintaan biaya. Ada empat langkah: Review, Edit, Confirm, dan Receipt. Pengguna mengharapkan satu hal: Back selalu kembali ke langkah sebelumnya, bukan ke layar acak yang pernah mereka kunjungi sebelumnya.

Enum route sederhana menjaga ini tetap dapat diprediksi. NavigationPath Anda harus menyimpan hanya route dan beberapa identifier kecil yang diperlukan untuk memuat ulang state, seperti expenseID dan mode (review vs edit). Hindari mempush model besar yang dapat berubah ke dalam path karena itu membuat restore dan deep link rapuh.

Simpan draft kerja di satu sumber kebenaran di luar view, seperti @StateObject model alur (atau store). Setiap langkah membaca dan menulis model itu, sehingga layar bisa muncul dan menghilang tanpa kehilangan input.

Setidaknya, Anda melacak tiga hal:

  • Routes (misalnya: review(expenseID), edit(expenseID), confirm(expenseID), receipt(expenseID))
  • Data (objek draft dengan line items dan catatan, plus status seperti pending, approved, rejected)
  • Lokasi (draft di model alur Anda, record kanonis di server, dan token restore lokal kecil: expenseID + langkah terakhir)

Edge case adalah tempat alur membangun atau merusak kepercayaan pengguna. Jika manajer menolak di Confirm, putuskan apakah Back mengembalikan ke Edit (untuk memperbaiki) atau keluar dari alur. Jika mereka kembali nanti, restore langkah terakhir dari token yang disimpan dan muat ulang draft. Jika mereka berpindah perangkat, anggap server sebagai sumber kebenaran: rekonstruksi path dari status server dan arahkan mereka ke langkah yang tepat.

Langkah selanjutnya: dokumentasikan enum route Anda (apa arti tiap case dan kapan digunakan), tambahkan beberapa tes dasar untuk membangun path dan perilaku restore, dan patuhi satu aturan: view tidak memiliki keputusan navigasi.

Jika Anda membangun jenis alur multi-langkah yang sama tanpa menulis semuanya dari awal, platform seperti AppMaster (appmaster.io) menerapkan pemisahan yang sama: jaga navigasi langkah dan data bisnis terpisah sehingga layar bisa berubah tanpa merusak progres pengguna.

FAQ

Bagaimana cara menjaga tombol Kembali agar dapat diprediksi dalam alur multi-langkah SwiftUI?

Gunakan NavigationStack dengan satu NavigationPath yang Anda kendalikan. Tambahkan tepat satu route untuk setiap aksi “Next” dan pop tepat satu route untuk setiap aksi Kembali. Jika perlu melompat (mis. “Edit profil” dari layar Review), potong path ke indeks yang diketahui daripada menumpuk layar baru.

Mengapa data formulir saya hilang saat saya menekan kembali?

Karena SwiftUI membangun ulang destination view dari nilai route, bukan dari instance view yang tetap hidup. Jika data form Anda disimpan di @State view, ia bisa menyetel ulang saat view direkonstruksi. Letakkan data draft di model bersama (mis. ObservableObject) yang hidup di luar view yang dipush.

Mengapa saya melihat layar yang sama dua kali dalam stack?

Biasanya terjadi ketika Anda menambahkan route yang sama lebih dari sekali (sering karena ketukan cepat atau beberapa jalur kode memicu navigasi). Nonaktifkan tombol Next saat sedang menavigasi atau saat validasi/loading berjalan, dan pusatkan mutasi navigasi agar hanya satu append terjadi per langkah.

Apa yang harus saya simpan di enum route dan apa yang harus saya keluarkan darinya?

Simpan nilai routing yang kecil dan stabil seperti kasus enum plus ID ringan. Simpan data yang dapat berubah (draft) di objek bersama terpisah dan ambil datanya berdasarkan ID bila perlu. Menaruh model besar yang berubah ke dalam path bisa merusak asumsi Hashable dan menyebabkan destination mismatch.

Bagaimana cara memisahkan navigation state dari flow state dengan rapi?

Navigasi adalah “di mana pengguna berada,” dan state alur adalah “apa yang mereka masukkan.” Miliki path navigasi di router (atau state top-level) dan miliki draft di ObservableObject terpisah. Setiap layar mengubah draft; router hanya mengubah langkah.

Apa cara paling aman untuk menangani deep link ke langkah 3 dari wizard?

Perlakukan deep link sebagai instruksi untuk membangun urutan langkah yang valid, bukan teleport ke satu layar. Bangun path dengan menambahkan langkah prasyarat terlebih dahulu (berdasarkan apa yang sudah pengguna selesaikan), lalu tambahkan langkah target. Ini menjaga back stack konsisten dan menghindari state yang tidak valid.

Bagaimana saya memulihkan alur yang belum selesai setelah aplikasi dimulai ulang?

Simpan dua hal: langkah terakhir yang bermakna (atau identifier langkah) dan data draft. Saat diluncurkan kembali, bangun kembali path menggunakan pemeriksaan prasyarat yang sama seperti saat menangani deep link, lalu muat draft. Jika draft sudah lama, memulai ulang alur tetapi mengisi field terlebih dahulu seringkali kurang membingungkan daripada menempatkan pengguna di tengah wizard.

Kapan saya harus push versus present modal dalam alur multi-langkah?

Push untuk jalur utama sehingga tombol Kembali menelusuri kembali alur secara alami. Gunakan sheet untuk tugas sampingan opsional dan fullScreenCover untuk pengalaman terpisah seperti login atau pengambilan gambar. Hindari meletakkan langkah inti di modal karena gesture dismiss bisa membuat UI dan state alur tidak sinkron.

Haruskah saya menimpa gesture kembali untuk menampilkan dialog “Anda yakin?”?

Jangan intercept Back secara default; biarkan perilaku sistem bekerja. Tambahkan konfirmasi hanya bila meninggalkan layar akan menyebabkan hilangnya pekerjaan yang berarti, dan hanya bila layar benar-benar “dirty.” Lebih baik gunakan autosave atau penyimpanan draft jika Anda sering perlu menampilkan konfirmasi.

Apa kesalahan paling umum yang menyebabkan bug back stack yang aneh?

Penyebab umum adalah menumpuk beberapa NavigationStack, mere-inisialisasi NavigationPath saat view diperbarui, dan memiliki beberapa pemilik yang memutasi path. Gunakan satu stack per alur, simpan path di state yang lebih tahan lama (@StateObject atau router tunggal), dan pusatkan logika push/pop di satu tempat.

Mudah untuk memulai
Ciptakan sesuatu yang menakjubkan

Eksperimen dengan AppMaster dengan paket gratis.
Saat Anda siap, Anda dapat memilih langganan yang tepat.

Memulai