NavigationStack یک کانتینر ناوبری مدرن در SwiftUI است که در iOS 16+ معرفی شده و جایگزین NavigationView شده است. به گزارش Apple Developer Documentation, 2024، NavigationStack پیشران نمایش را از طریق یک مسیر ناوبری ایمن از نظر نوع (NavigationPath) مدیریت میکند، از ناوبری عمیق، بازگشت برنامهای به نمایش اصلی و حفظ وضعیت هنگام تغییر دادهها پشتیبانی میکند. بر خلاف NavigationView، NavigationStack نیازی به پیچیدن در کانتینر اضافهای ندارد و Binding مستقیم به مسیر ناوبری ارائه میدهد.
نکات کلیدی
NavigationStack یک View کانتینری است که ناوبری بر پایه پیشران (LIFO) را پیادهسازی میکند. آن تاریخچه انتقالها را مدیریت میکند و به شما امکان قرار دادن نمایشهای جدید روی پیشران و بازگشت با دکمه «بازگشت» یا بهصورت برنامهای را میدهد. NavigationStack بخشی از SwiftUI از iOS 16، iPadOS 16، macOS 13، watchOS 9 و tvOS 16 است.
نوآوری اصلی NavigationStack مسیر ناوبری ایمن از نظر نوع است. به جای اشاره مستقیم به destination هنگام ایجاد NavigationLink، شما یک مقدار (value) را در مسیر قرار میدهید و ثبت View مقصد بهطور جداگانه از طریق مودیفیکاتور .navigationDestination(for:destination:) انجام میشود. این ناوبری و نمایش را از هم جدا میکند و کد را بیشتر ماژولار و قابل آزمایش میکند.
به گزارش WWDC 2022 (Session 10054)، NavigationStack از یک مکانیسم ناوبری جدید مبتنی بر ObservableObject و چرخه عمر SwiftUI استفاده میکند. بر خلاف NavigationView که به UINavigationController در زیرساخت متکی بود، NavigationStack تماماً در SwiftUI پیادهسازی شده است که قابل پیشبینی و سازگاری با چرخه عمر SwiftUI را بهبود میبخشد.
NavigationStack یک View اصلی و یک مسیر ناوبری اختیاری (Binding به NavigationPath یا ماسیو مقادیر Hashable) را میپذیرد. تمام نمایشهای فرعی از طریق NavigationLink یا افزودن برنامهای مقادیر به مسیر در پیشران قرار میگیرند.
NavigationView تا iOS 16 کانتینر اصلی ناوبری SwiftUI بود. آن بهطور خودکار UINavigationController را در زیرساخت مدیریت میکرد که به یک سری مشکلات منجر میشد: رفتار غیرقابل پیشبینی هنگام تغییر دادهها، مشکلات در ناوبری برنامهای و نبود ایمنی نوع.
| ویژگی | NavigationStack (iOS 16+) | NavigationView (iOS 13–15) |
|---|---|---|
| نوع ناوبری | پیشران (LIFO) | پیشران (LIFO) |
| مسیر ناوبری | تایپدار (NavigationPath) | پشتیبانی نمیشود |
| Deep linking | پشتیبانی توامخورده | نیازمند راهکارهاست |
| بازگشت برنامهای | از طریق مسیر (pop, popToRoot) | dismiss, presentationMode |
| زیرساخت | SwiftUI native | UINavigationController |
| سازگاری | iOS 16+ | iOS 13+ |
مزیت کلیدی NavigationStack — ناوبری ایمن از نظر نوع. شما مسیر را به عنوان ماسیوی از نوعهای مشخص (یا NavigationPath برای پیشرانهای ناهمگون) تعریف کرده و destination را برای هر نوع ثبت میکنید. این خطاهای ناهمخوانی نوع را از بین میبرد و ناوبری را قابل پیشبینی میکند.
NavigationView در iOS 17 منسوخ شده است. Apple توصیه میکند برای تمام پروژههای جدید و هنگام بهروزرسانی نسخه حداقل به iOS 16 به NavigationStack مهاجرت کنید.
NavigationPath نوعی است که مسیر ناوبری را در NavigationStack نمایش میدهد. آن میتواند مقادیر ناهمگون (AnyHashable) را ذخیره کند یا با یک نوع مشخص از طریق Binding به ماسیو [T: Hashable] استفاده شود. NavigationPath برای حفظ وضعیت بهطور خودکار کدگذاری و رمزگشایی میشود.
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")
}
}
پیشران ناهمگون: NavigationPath میتواند مقادیر از نوعهای مختلف را داشته باشد، اگر Hashable را پیاده کنند. به عنوان مثال، نمایش اول میتواند String (ID)، دومی — Int (شماره)، سومی — enum Route سفارشی را بپذیرد. برای نمایش هر نوع، یک .navigationDestination جداگانه ثبت میشود.
پشتیبانی Codable: NavigationPath Codable را پیاده میکند اگر تمام مقادیر در مسیر نیز Codable + Hashable باشند. این امکان ذخیره و بازیابی وضعیت ناوبری را در زمان راهاندازی مجدد برنامه یا ورود به حالت زمینه فراهم میکند.
.navigationDestination(for:destination:) — مودیفیکاتوری است که View مقصد را برای یک نوع داده مشخص ثبت میکند. وقتی NavigationLink یک مقدار از این نوع را در مسیر قرار میدهد، SwiftUI بهطور خودکار .navigationDestination مربوطه را پیدا کرده و نمایش را ایجاد میکند.
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"))
قاعده مهم: .navigationDestination باید به Viewی اعمال شود که داخل NavigationStack قرار دارد، قبل از اینکه NavigationLink مقداری را در مسیر قرار دهد. معمولاً آن را به View اصلی یا کانتینر بخش اضافه میکنند. اگر .navigationDestination برای نوع مقدار پیدا نشود، انتقال انجام نمیشود.
به گزارش SwiftUI Engineering (2023)، .navigationDestination میتواند در سطحهای مختلف سلسلهمراتب ثبت شود. SwiftUI در زمان تلاش برای ناوبری، نزدیکترین destination مناسب را جستجو میکند. این امکان بازنویسی destination را برای یک نوع در بخشهای مختلف برنامه فراهم میکند.
الگوی 1: ناوبری از طریق Route. یک enum با مقادیر همراه برای تمام نمایشهای برنامه تعریف کنید. از یک .navigationDestination برای AppRoute و switch برای مسیریابی استفاده کنید. این یک منبع واحد حقیقت برای تمام انتقالهای ممکن در برنامه فراهم میکند.
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)
}
الگوی 2: ناوبری برنامهای و deep linking. NavigationStack امکان مدیریت برنامهای پیشران را فراهم میکند: افزودن، حذف نمایشها و بازگشت به ریشه. این برای اعلانهای push، لینکهای عمیق و بازیابی ناوبری پس از راهاندازی مجدد ضروری است.
الگوی 3: ماسیو نوعها به جای NavigationPath. اگر تمام نمایشها از یک نوع استفاده میکنند (مثل String یا یک enum سفارشی)، از Binding به [T] استفاده کنید. این نسبت به NavigationPath نوعبندی سخیتر و عملکرد بهتری ارائه میدهد. NavigationPath برای پیشرانهای ناهمگون با نوعهای مختلف توصیه میشود.
به گزارش Point-Free (2024)، NavigationStack با enum Route روش ترجیحی سازماندهی ناوبری در برنامههای SwiftUI است. تمام انتقالهای ممکن را صریح، ایمن از نظر نوع و قابل آزمایش میکند که بهویژه برای پروژههای بزرگ با دهها نمایش مهم است.
سوالات متداول
NavigationStack — کانتینر ناوبری SwiftUI (iOS 16+)، پیشران نمایش را از طریق یک مسیر ایمن از نظر نوع مدیریت میکند. جایگزین NavigationView شده و پشتیبانی از deep linking، ناوبری برنامهای و ذخیره وضعیت را فراهم میکند.
NavigationStack به جای پیوند مستقیم NavigationLink با destination، از یک مسیر ایمن از نظر نوع (NavigationPath) استفاده میکند. از ناوبری برنامهای، deep linking و Codable برای ذخیره وضعیت پشتیبانی میکند. آن به جای UINavigationController بر روی SwiftUI کار میکند.
NavigationPath نوعی است که تسلسل نمایشها را در پیشران نشان میدهد. شما مقادیر را از طریق path.append() یا NavigationLink با value به مسیر اضافه میکنید. برای نمایش هر نوع، .navigationDestination ثبت میشود. NavigationPath از Codable و ذخیره خودکار وضعیت پشتیبانی میکند.
از طریق مدیریت برنامهای مسیر: پس از پردازش URL، path.append() را با مقدار مسیر مربوطه فراخوان کنید. NavigationStack بهطور خودکار نمایش مقصد را نمایش میدهد. بازگشت به ریشه — path.removeLast(path.count).
بله، اگر حداقل نسخه شما iOS 16+ است. NavigationView در iOS 17 منسوخ شده است. مهاجرت ناوبری ایمن از نظر نوع، پشتیبانی از deep linking و سازگاری بهتر با چرخه عمر SwiftUI را فراهم میکند. برای پروژههایی با iOS 15 و پایینتر، هنوز از NavigationView استفاده کنید.
نتیجه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید