SwiftUI یک فریمورک اعلانی (دکالریتیو) از اپل برای ساخت رابطهای کاربری در تمام پلتفرمهای اکوسیستم است. به جای توصیف گامهای امری، توسعهدهنده اعلام میکند که رابط کاربری چگونه باید به نظر برسد و SwiftUI رندر کردن و بهروزرسانی آن را مدیریت میکند. به گزارش Apple Developer Documentation (2025)، SwiftUI از iOS 15+، iPadOS 15+، macOS 12+، watchOS 8+ و tvOS 15+ پشتیبانی میکند و از View Protocol به عنوان بلوک ساختمانی پایه برای تمام مؤلفههای رابط استفاده میکند.
نکات اصلی
body — اساس هر مؤلفه UI در SwiftUI که توصیف صفحه را از طریق ترکیب ویوها برمیگرداند.SwiftUI یک فریمورک اعلانی است که توسط اپل در سال ۲۰۱۹ برای جایگزینی UIKit در پروژههای جدید معرفی شد. به جای ایجاد دستی نمونههای UIView و اضافه کردن آنها به سلسلهمراتب، توسعهدهنده رابط را از طریق ساختارهایی که پروتکل View را پیادهسازی میکنند توصیف میکند. SwiftUI به طور خودکار تفاوت بین وضعیت فعلی و جدید را محاسبه کرده و فقط قسمتهای تغییر یافته را با استفاده از موتور رندر خود بازرَنی میکند.
این فریمورک در Swift با استفاده از value semantics (ساختارها، نه کلاسها) نوشته شده است که مؤلفههای UI را سبک و thread-safe میکند. برخلاف UIKit که در آن UIViewController به دلیل Objective-C runtime میتواند ۲۰۰+ بایت وزن داشته باشد، View در SwiftUI فقط یک ساختار با اندازه چند بایت است. این به ویژه برای watchOS با حافظه محدود آن مهم است.
همان توصیف View در iPhone، iPad، Mac، Apple Watch، Apple TV و Apple Vision Pro کار میکند. SwiftUI رابط را با پلتفرم تطبیق میدهد: در iOS — ژستهای لمسی، در macOS — میانبرهای صفحه کلید، در watchOS — پیمایش Digital Crown. این زمان توسعه را برای شرکتهایی که برنامههایی برای چندین پلتفرم اپل منتشر میکنند کاهش میدهد، اما برای عناصر خاص هر پلتفرم نیاز به پیکربندی اضافی دارد.
در SwiftUI هر صفحه یک ساختار است که پروتکل View را با یک نیاز واحد پیادهسازی میکند: computed property body از نوع some View. کلمه کلیدی some (opaque type) نوع خاص ویو را پنهان میکند و به SwiftUI امکان بهینهسازی رندر را میدهد. در داخل body، توسعهدهنده مؤلفههای آماده — Text، Image، Button، List — را با استفاده از ViewBuilder ترکیب میکند که چندین ویو را در یکی جمع میکند.
struct GreetingView: View {
let name: String
var var body: some View {
VStack {
Text("سلام، \(name)!")
.font(.title)
.foregroundColor(.blue)
Image(systemName: "hand.wave")
.imageScale(.large)
}
.padding()
}
}
در مثال، VStack (پشته عمودی) شامل Text و Image است. مقدار name از طریق مقداردهنده اولیه ساختار منتقل میشود — این گونه DI (Dependency Injection) در SwiftUI بدون کانتینرهای DI خارجی کار میکند. هر اصلاحکننده یک ویو جدید با تغییر اعمال شده برمیگرداند، بدون اینکه اصل را تغییر دهد. این به لطف تغییرناپذیری (immutability) انواع value ممکن است.
ViewBuilder یک result builder است که با @resultBuilder نشانهگذاری شده و تا ۱۰ ویو را در یکی جمع میکند. در داخل body میتوان از if/else، switch و ForEach بدون پوششهای اضافی استفاده کرد. ForEach با عناصر Identifiable کار میکند — هر ویو برای انیمیشن صحیح در هنگام درج/حذف یک id منحصر به فرد دریافت میکند.
در SwiftUI وضعیت تعیین میکند چه محتوایی روی صفحه نمایش داده میشود. هنگامی که وضعیت تغییر میکند، SwiftUI body ویو وابسته را بازآفرینی کرده و نتیجه را با قبلی با استفاده از الگوریتم diff مقایسه میکند. برای ذخیره وضعیت از property wrappers استفاده میشود — هر کدام وظیفه خود را حل میکند: وضعیت محلی، ارتباط با ویو فرزند یا مدل داده خارجی.
struct CounterView: View {
@State private var count = 0
var var body: some View {
VStack {
Text("شمارنده: \(count)")
Button("افزایش") {
count += 1
}
}
}
}
class UserViewModel: ObservableObject {
@Published var name = ""
@Published var age = 0
}
@State یک مقدار محلی ساده (Int، String، Bool) را در داخل ساختار View ذخیره میکند. SwiftUI حافظه را از ساختار به یک انبار جداگانه منتقل میکند — بنابراین ویژگی با @State قابل تغییر (mutate) است، حتی اگر View یک type-value باشد. @ObservableObject — برای کلاسهایی با ویژگیهای @Published که تغییرات آنها به طور خودکار SwiftUI را از نیاز به بازرَنی مطلع میکند.
@Binding یک ارتباط دوطرفه با منبع داده واقع در ویو والد ایجاد میکند. والد $variable (projected value) را منتقل میکند، فرزند مقدار را از طریق binding میخواند و مینویسد. این امکان را فراهم میکند که ورود متن یا کلید را به یک مؤلفه جداگانه منتقل کرده و وضعیت را در والد حفظ کند. بدون @Binding هر تغییر نیاز به یک بسته callback برای انتقال مقدار جدید به بالا داشت.
قبل از iOS 16، ناوبری در SwiftUI بر روی NavigationView ساخته شده بود — API قدیمی با رفتار پیچیده در iPad (split view، double column). از iOS 16 به بعد، Apple NavigationStack را توصیه میکند — جایگزین سادهشده با مسیرهای نوع-امن. توسعهدهنده enum مسیرهای ممکن را تعریف میکند و NavigationStack به طور خودکار پشته صفحات را با پشتیبانی از لینکهای عمیق و بازگشت به ریشه مدیریت میکند.
enum Route: Hashable {
case detail(id: Int)
case settings
}
struct ContentView: View {
var var body: some View {
NavigationStack {
List {
NavigationLink("صفحه جزئیات",
value: Route.detail(id: 42))
NavigationLink("تنظیمات",
value: Route.settings)
}
.navigationDestination(for: Route.self) { route in
switch route {
case .detail(let id): DetailView(id: id)
case .settings: SettingsView()
}
}
}
}
}
مسیرهای نوع Route: Hashable امکان استفاده از هر نوع داده برای انتقال پارامترها را فراهم میکنند. navigationDestination(for:destination:) نوع مسیر را به ویو مقصد متصل میکند. مزیت نسبت به ناوبری UIKit — بازرَنی هنگام افزودن مسیر جدید لازم نیست: کافی است case در enum و handler در switch اضافه شود. لینکهای عمیق از طریق processDeepLink روی NavigationStack پردازش میشوند.
برای انتقال برنامهریزی شده (پس از ورود، تایمر یا پاسخ سرور) از @State با مقداردهنده NavigationLink استفاده میشود: NavigationLink(isActive: $isActive). با تنظیم isActive = true انتقال بدون لمس کاربر انجام میشود. جایگزین — binding آرایه $path در NavigationStack: $path.append(Route.detail(id: 1)).
Modifier متدی است که یک کپی تغییر یافته از ویو را برمیگرداند. برخلاف UIKit که در آن پیکربندی ویژگیها از طریق تغییر (mutate) ویو موجود انجام میشود، SwiftUI یک مقدار جدید با تغییر اعمال شده ایجاد میکند. زنجیره اصلاحکنندهها (chaining) رابط نهایی را از تبدیلهای متوالی میسازد: فونت → فاصله → رنگ → سایه → ژست.
Apple بیش از ۲۰۰ اصلاحکننده داخلی ارائه میدهد. رایجترینها: .font()، .foregroundColor()، .padding()، .background()، .cornerRadius()، .shadow()، .opacity()، .offset(). ترتیب اصلاحکنندهها مهم است: .padding() قبل از .background() ناحیه با فاصله را رنگ میکند، بعد از آن — فقط ناحیه داخلی. اصلاحکنندههای سفارشی از طریق پروتکل ViewModifier ایجاد میشوند.
اصلاحکنندهها را میتوان به صورت شرطی از طریق عملگر سهتایی اعمال کرد: .foregroundColor(isError ? .red : .primary). برای انیمیشن از .animation(.easeInOut, value: state) استفاده میشود — اصلاحکننده انیمیشن به ویژگی خاص وضعیت متصل میشود. با تغییر این ویژگی، SwiftUI انتقال بین مقدار قدیم و جدید را انیمیشن میکند. انیمیشن با opacity، offset، scale، rotation، اندازه و رنگ کار میکند — برای هر ویژگی یک AnimatableParameter مربوطه تعریف شده است.
برای انیمیشنهای سفارشی، .transition (ظاهر/ناپدید شدن) و .matchedGeometryEffect (انتقال روان عنصر بین دو کانتینر) در دسترس هستند. دومی برای انیمیشن hero در لیستها استفاده میشود: آیکون در سلول لیست به طور روان به یک تصویر بزرگ در صفحه جزئیات تبدیل میشود.
انتخاب بین SwiftUI و UIKit یکی از اولین دوراهیهای توسعهدهنده iOS است. هر دو فریمورک توسط اپل پشتیبان میشوند، اما وظیفه ساخت رابط را به روشهای اساساً متفاوت حل میکنند: SwiftUI به صورت اعلانی، UIKit به صورت امری. تفاوت در مدیریت وضعیت، ناوبری، عملکرد و سازگاری نمایان میشود.
| جنبه | SwiftUI | UIKit |
|---|---|---|
| رویکرد | اعلانی: چه چیزی نشان داده شود | امری: چگونه ساخته شود |
| وضعیت | Property Wrappers، بازرَنی خودکار | دستی: reloadData، setNeedsLayout |
| کد UI | فشرده، زنجیره اصلاحکنندهها | حجیم، NSCoder/Storyboard/محدودیتها |
| عملکرد | بالا در iOS 17+، الگوریتم diff | اوج در iOS 12–16، کنترل مستقیم |
| حداقل نسخه | iOS 15+ (پشتیبانی کامل) | iOS 2+ (همه نسخهها) |
برای پروژههای جدید با حداقل نسخه iOS 17، اپل SwiftUI را به عنوان فریمورک اصلی توصیه میکند. UIKit برای رابطهایی که نیاز به کنترل دقیق روی رندر دارند (UICollectionViewLayout سفارشی، صحنههای پیچیده CAAnimation) یا پشتیبانی از iOS 12–14 ضروری باقی میماند. بسیاری از پروژهها از رویکرد هیبریدی استفاده میکنند: SwiftUI از طریق UIHostingController در برنامه UIKit جاسازی میشود و UIViewRepresentable امکان استفاده از مؤلفههای UIKit را در سلسلهمراتب SwiftUI فراهم میکند.
سوالات متداول
بله، از طریق UIHostingController (SwiftUI در UIKit) و UIViewRepresentable (UIKit در SwiftUI). این یک رویکرد هیبریدی است که در مهاجرت محبوب است.
iOS 17 — عملکرد کامل: NavigationStack، Observation framework، Swift Charts. iOS 15 — حداقل آستانه برای تولید.
شایعترین دلیل تغییر ویژگی @Published در نخ پسزمینه است. ObservableObject باید تغییرات را روی main actor ارسال کند: @MainActor class ViewModel.
از .debounce از طریق Combine استفاده کنید: Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main).
بله، از طریق اصلاحکنندههای Gesture: DragGesture، LongPressGesture، MagnificationGesture، RotationGesture. آنها را از طریق .simultaneousGesture() و .sequenced() ترکیب کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.