SwiftUI: چیست، مفاهیم کلیدی و View Protocol

نویسنده: IT Sectr منتشر شده: 2026-04-30 زمان مطالعه: 8 دقیقه

SwiftUI یک فریم‌ورک اعلانی (دکالریتیو) از اپل برای ساخت رابط‌های کاربری در تمام پلتفرم‌های اکوسیستم است. به جای توصیف گام‌های امری، توسعه‌دهنده اعلام می‌کند که رابط کاربری چگونه باید به نظر برسد و SwiftUI رندر کردن و به‌روزرسانی آن را مدیریت می‌کند. به گزارش Apple Developer Documentation (2025)، SwiftUI از iOS 15+، iPadOS 15+، macOS 12+، watchOS 8+ و tvOS 15+ پشتیبانی می‌کند و از View Protocol به عنوان بلوک ساختمانی پایه برای تمام مؤلفه‌های رابط استفاده می‌کند.

نکات اصلی

  • SwiftUI — فریم‌ورک اعلانی اپل که در آن توسعه‌دهنده رابط را توصیف می‌کند و به‌روزرسانی‌ها به صورت خودکار انجام می‌شوند.
  • View Protocol با property body — اساس هر مؤلفه UI در SwiftUI که توصیف صفحه را از طریق ترکیب ویوها برمی‌گرداند.
  • Property Wrappers — @State، @Binding، @ObservedObject، @StateObject — وضعیت را مدیریت کرده و با تغییر داده‌ها بازرَنی را آغاز می‌کنند.
  • NavigationStack (iOS 16+) — API ناوبری مدرن با مسیرهای نوع-امن و انتقال‌های اعلانی.
  • Modifier — زنجیره فراخوانی برای پیکربندی ظاهر و رفتار ویوها بدون وراثت کلاس.

SwiftUI چیست؟

SwiftUI یک فریم‌ورک اعلانی است که توسط اپل در سال ۲۰۱۹ برای جایگزینی UIKit در پروژه‌های جدید معرفی شد. به جای ایجاد دستی نمونه‌های UIView و اضافه کردن آنها به سلسله‌مراتب، توسعه‌دهنده رابط را از طریق ساختارهایی که پروتکل View را پیاده‌سازی می‌کنند توصیف می‌کند. SwiftUI به طور خودکار تفاوت بین وضعیت فعلی و جدید را محاسبه کرده و فقط قسمت‌های تغییر یافته را با استفاده از موتور رندر خود بازرَنی می‌کند.

این فریم‌ورک در Swift با استفاده از value semantics (ساختارها، نه کلاس‌ها) نوشته شده است که مؤلفه‌های UI را سبک و thread-safe می‌کند. برخلاف UIKit که در آن UIViewController به دلیل Objective-C runtime می‌تواند ۲۰۰+ بایت وزن داشته باشد، View در SwiftUI فقط یک ساختار با اندازه چند بایت است. این به ویژه برای watchOS با حافظه محدود آن مهم است.

چندپلتفرمی SwiftUI

همان توصیف View در iPhone، iPad، Mac، Apple Watch، Apple TV و Apple Vision Pro کار می‌کند. SwiftUI رابط را با پلتفرم تطبیق می‌دهد: در iOS — ژست‌های لمسی، در macOS — میانبرهای صفحه کلید، در watchOS — پیمایش Digital Crown. این زمان توسعه را برای شرکت‌هایی که برنامه‌هایی برای چندین پلتفرم اپل منتشر می‌کنند کاهش می‌دهد، اما برای عناصر خاص هر پلتفرم نیاز به پیکربندی اضافی دارد.

View Protocol و بدنه نمایش

در SwiftUI هر صفحه یک ساختار است که پروتکل View را با یک نیاز واحد پیاده‌سازی می‌کند: computed property body از نوع some View. کلمه کلیدی some (opaque type) نوع خاص ویو را پنهان می‌کند و به SwiftUI امکان بهینه‌سازی رندر را می‌دهد. در داخل body، توسعه‌دهنده مؤلفه‌های آماده — Text، Image، Button، List — را با استفاده از ViewBuilder ترکیب می‌کند که چندین ویو را در یکی جمع می‌کند.

swift
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 و شرط‌ها

ViewBuilder یک result builder است که با @resultBuilder نشانه‌گذاری شده و تا ۱۰ ویو را در یکی جمع می‌کند. در داخل body می‌توان از if/else، switch و ForEach بدون پوشش‌های اضافی استفاده کرد. ForEach با عناصر Identifiable کار می‌کند — هر ویو برای انیمیشن صحیح در هنگام درج/حذف یک id منحصر به فرد دریافت می‌کند.

مدیریت وضعیت: @State، @Binding، @ObservedObject

در SwiftUI وضعیت تعیین می‌کند چه محتوایی روی صفحه نمایش داده می‌شود. هنگامی که وضعیت تغییر می‌کند، SwiftUI body ویو وابسته را بازآفرینی کرده و نتیجه را با قبلی با استفاده از الگوریتم diff مقایسه می‌کند. برای ذخیره وضعیت از property wrappers استفاده می‌شود — هر کدام وظیفه خود را حل می‌کند: وضعیت محلی، ارتباط با ویو فرزند یا مدل داده خارجی.

swift
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 و ارتباط والد-فرزند

@Binding یک ارتباط دوطرفه با منبع داده واقع در ویو والد ایجاد می‌کند. والد $variable (projected value) را منتقل می‌کند، فرزند مقدار را از طریق binding می‌خواند و می‌نویسد. این امکان را فراهم می‌کند که ورود متن یا کلید را به یک مؤلفه جداگانه منتقل کرده و وضعیت را در والد حفظ کند. بدون @Binding هر تغییر نیاز به یک بسته callback برای انتقال مقدار جدید به بالا داشت.

قبل از iOS 16، ناوبری در SwiftUI بر روی NavigationView ساخته شده بود — API قدیمی با رفتار پیچیده در iPad (split view، double column). از iOS 16 به بعد، Apple NavigationStack را توصیه می‌کند — جایگزین ساده‌شده با مسیرهای نوع-امن. توسعه‌دهنده enum مسیرهای ممکن را تعریف می‌کند و NavigationStack به طور خودکار پشته صفحات را با پشتیبانی از لینک‌های عمیق و بازگشت به ریشه مدیریت می‌کند.

swift
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)).

View Modifier — پیکربندی ظاهر

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 vs UIKit: مقایسه رویکردها

انتخاب بین SwiftUI و UIKit یکی از اولین دوراهی‌های توسعه‌دهنده iOS است. هر دو فریم‌ورک توسط اپل پشتیبان می‌شوند، اما وظیفه ساخت رابط را به روش‌های اساساً متفاوت حل می‌کنند: SwiftUI به صورت اعلانی، UIKit به صورت امری. تفاوت در مدیریت وضعیت، ناوبری، عملکرد و سازگاری نمایان می‌شود.

جنبهSwiftUIUIKit
رویکرداعلانی: چه چیزی نشان داده شودامری: چگونه ساخته شود
وضعیت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 فراهم می‌کند.

سوالات متداول

آیا می‌توان SwiftUI و UIKit را در یک پروژه استفاده کرد؟

بله، از طریق UIHostingController (SwiftUI در UIKit) و UIViewRepresentable (UIKit در SwiftUI). این یک رویکرد هیبریدی است که در مهاجرت محبوب است.

از چه نسخه iOS پروژه SwiftUI را شروع کنیم؟

iOS 17 — عملکرد کامل: NavigationStack، Observation framework، Swift Charts. iOS 15 — حداقل آستانه برای تولید.

چرا SwiftUI گاهی رابط را به‌روز نمی‌کند؟

شایع‌ترین دلیل تغییر ویژگی @Published در نخ پس‌زمینه است. ObservableObject باید تغییرات را روی main actor ارسال کند: @MainActor class ViewModel.

چگونه در SwiftUI فشار دکمه با تأخیر را پردازش کنیم؟

از .debounce از طریق Combine استفاده کنید: Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main).

آیا SwiftUI از ژست‌های سفارشی پشتیبانی می‌کند؟

بله، از طریق اصلاح‌کننده‌های Gesture: DragGesture، LongPressGesture، MagnificationGesture، RotationGesture. آنها را از طریق .simultaneousGesture() و .sequenced() ترکیب کنید.

خلاصه

  • SwiftUI — فریم‌ورک اعلانی اپل که در آن رابط به صورت ترکیبی از ساختارهای View با property wrappers برای مدیریت وضعیت توصیف می‌شود.
  • View Protocol با computed property body — تنها نقطه ورود برای هر ویو. ViewBuilder تا ۱۰ ویو را بدون کانتینر اضافی در یکی جمع می‌کند.
  • @State، @Binding و @ObservedObject تمام سناریوهای مدیریت داده را پوشش می‌دهند: وضعیت محلی، ارتباط والد-فرزند و مدل‌های خارجی.
  • NavigationStack با مسیرهای enum نوع-امن جایگزین NavigationView شد و پشتیبانی از لینک‌های عمیق و ناوبری برنامه‌ریزی شده را اضافه کرد.
  • Modifier — الگوی کلیدی SwiftUI که امکان پیکربندی ظاهر ویوها را از طریق زنجیره فراخوانی بدون وراثت فراهم می‌کند.
  • SwiftUI و UIKit از طریق UIHostingController و UIViewRepresentable همزیستی دارند و امکان مهاجرت تدریجی پروژه را فراهم می‌کنند.
  • برای iOS 17+ اپل SwiftUI را به عنوان فریم‌ورک اصلی توصیه می‌کند؛ UIKit برای رابط‌های سفارشی پیچیده و پشتیبانی از نسخه‌های قدیمی باقی می‌ماند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید