SwiftUI — مفاهیم کلیدی، View، State و Data Flow

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

SwiftUI — فریم‌ورک اعلامی اپل برای ساخت رابط‌های کاربری در تمام پلتفرم‌های اکوسیستم، که در WWDC 2019 معرفی شد. برخلاف UIKit امری با viewDidLoad و به‌روزرسانی دستی صفحه، SwiftUI رابط کاربری را به عنوان مجموعه‌ای از ساختارهای ساده مطابق با پروتکل View توصیف می‌کند. طبق Swift.org (2025)، SwiftUI در 65٪ پروژه‌های جدید منتشر شده در App Store استفاده می‌شود. این فریم‌ورک به‌طور خودکار به‌روزرسانی رابط را از طریق مکانیسم State و Data Flow مدیریت می‌کند — با تغییر داده‌ها، View بدون فراخوانی دستی reloadData دوباره ترسیم می‌شود.

نکات اصلی

  • SwiftUI — فریم‌ورک اعلامی اپل برای UI (2019)، که در آن رابط با ساختارهای مطابق با پروتکل View توصیف می‌شود.
  • View — بلوک ساختمانی پایه SwiftUI؛ هر View بخش خود از صفحه را از طریق computed property body توصیف می‌کند.
  • @State — property wrapper برای ذخیره وضعیت محلی، که با تغییر آن View به‌طور خودکار دوباره ترسیم می‌شود.
  • @Binding — ارتباط دوطرفه بین View و داده‌ها که به View فرزند اجازه می‌دهد وضعیت والد را تغییر دهد.
  • @ObservedObject و @StateObject — ارتباط با مدل‌های داده خارجی از طریق کلاس‌های مطابق با پروتکل ObservableObject.

SwiftUI چیست؟

SwiftUI — فریم‌ورک UI اعلامی اپل که تفاوت اساسی با UIKit دارد. به جای ایجاد کنترلرها، ویوها و مدیریت دستی چرخه حیات آنها، توسعه‌دهنده رابط را به صورت اعلامی توصیف می‌کند: چه چیزی باید روی صفحه باشد، نه چگونه آن را بسازد. SwiftUI بر اساس اصل واکنش‌گرایی استوار است: رابط تابعی از وضعیت است. با تغییر وضعیت (State)، SwiftUI به‌طور خودکار body تمام Viewهای وابسته را محاسبه مجدد می‌کند و فقط بخش‌های تغییر یافته صفحه را به‌روزرسانی می‌کند. SwiftUI در iOS 13+، iPadOS 13+، macOS 10.15+، watchOS 6+، tvOS 13+ و visionOS 1+ در دسترس است. کد SwiftUI چندپلتفرمی است: یک فایل با حداقل تطبیق‌های پلتفرمی در iPhone، iPad، Mac و Apple Watch کار می‌کند. طبق Apple WWDC Session 101 (2024)، SwiftUI بیش از 90٪ از الگوهای UI استاندارد App Store را پوشش می‌دهد.

SwiftUI در مقابل UIKit

UIKit — فریم‌ورک امری (2008): توسعه‌دهنده UIViewController ایجاد می‌کند، subviews را در viewDidLoad پیکربندی می‌کند، delegate/datasource را برای UITableView پیاده‌سازی می‌کند و صفحه را از طریق reloadData یا setNeedsLayout به‌روزرسانی می‌کند. SwiftUI کنترلرها را با ساختارهای ساده View، دلیگیت‌ها را با binding و onChange، Auto Layout را با HStack/VStack/ZStack با modifierها (padding, frame, offset) جایگزین می‌کند. UIKit نیاز به مدیریت دستی حافظه از طریق ARC دارد؛ SwiftUI — ساختارهایی که نیاز به شمارش مراجع ندارند. عملکرد SwiftUI قابل مقایسه با UIKit است: فریم‌ورک از الگوریتم diffing برای حداقل مجموعه تغییرات استفاده می‌کند. در IT Sectr از SwiftUI برای پروژه‌های جدید با target iOS 17+ استفاده می‌شود؛ پروژه‌های با پشتیبانی iOS 14-15 به دلیل سازگاری محدود SwiftUI نیاز به UIKit دارند.

سینتکس اعلامی SwiftUI

در SwiftUI رابط از طریق ViewBuilder توصیف می‌شود — result builder که مجموعه‌ای از View را به tuple یا Group تبدیل می‌کند. Modifierها (.padding()، .font()، .foregroundColor()) View جدیدی با تنظیمات تغییر یافته ایجاد می‌کنند، نه اینکه شیء اصلی را تغییر دهند. هر modifier یک View جدید برمی‌گرداند که امکان زنجیره‌ای شدن را فراهم می‌کند. ViewBuilder از if/else، switch، ForEach پشتیبانی می‌کند — رندر شرطی و حلقوی بدون کنترلرهای جداگانه. View در SwiftUI یک value type (struct) است که رفتار قابل پیش‌بینی را تضمین می‌کند و race conditions را حذف می‌کند.

پروتکل View و computed property body

View — پروتکلی با یک نیاز: computed property body از نوع some View. هر ساختار مطابق با View بخش خود از صفحه را در body توصیف می‌کند. نوع some View — opaque return type که نوع خاص View برگشتی را پنهان می‌کند (ترکیب VStack، HStack، ZStack، Text، Image و غیره). کامپایلر Swift نوع خاص را در زمان کامپایل استنتاج می‌کند و عملکرد فراخوانی مستقیم بدون پاک شدن نوع را حفظ می‌کند.

swift
import SwiftUI

struct GreetingView: View {
    var name: String
    
    var body: some View {
        VStack(spacing: 12) {
            Text("سلام، \(name)!")
                .font(.largeTitle)
                .foregroundColor(.primary)
            
            Text("به SwiftUI خوش آمدید")
                .font(.body)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(.ultraThinMaterial)
        )
    }
}

ساختار GreetingView پارامتر name را می‌پذیرد و دو بلوک متنی را در یک پشته عمودی نمایش می‌دهد. Modifierهای .font، .foregroundColor، .padding و .background ظاهر را پیکربندی می‌کنند. SwiftUI body را هر بار با تغییر پارامترهای ورودی (name) فراخوانی می‌کند — ترسیم مجدد فقط برای بخش‌های تغییر یافته رخ می‌دهد. در مثال از RoundedRectangle با .ultraThinMaterial استفاده شده است — پس‌زمینه blur بومی ساخته شده در SwiftUI.

@State: وضعیت محلی در SwiftUI

@State — property wrapper که وضعیت محلی متعلق به یک View را اعلام می‌کند. SwiftUI حافظه State را به‌طور خودکار مدیریت می‌کند: با تغییر مقدار، body دوباره ترسیم می‌شود، اما فقط برای Viewهایی که از این State استفاده می‌کنند. State منبع حقیقت (source of truth) برای انواع ساده (String، Int، Bool، enum) است. برای مدل‌های داده پیچیده از @State استفاده نکنید — برای آنها @StateObject و @ObservedObject در نظر گرفته شده است. State باید private باشد و در خود View ذخیره شود، نه بین کامپوننت‌ها منتقل شود.

swift
import SwiftUI

struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("تعداد: \(count)")
                .font(.system(size: 48, weight: .bold))
            
            Button(action: { count += 1 }) {
                Label("افزایش", systemImage: "plus.circle")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

مقدار اولیه count = 0. هر بار کلیک دکمه count را افزایش می‌دهد؛ SwiftUI به‌طور خودکار CounterView را به طور کامل (همه Viewها) دوباره ترسیم می‌کند. در UIKit سناریوی مشابه به IBOutlet، IBAction و به‌روزرسانی دستی label.text نیاز داشت. @State تضمین می‌کند که View فقط با تغییر State خاص دوباره ترسیم می‌شود — الگوریتم diffing SwiftUI حداقل تغییرات را در درخت پیدا می‌کند.

@Binding: ارتباط دوطرفه بین View

@Binding — property wrapper که ارتباط دوطرفه بین View و داده‌هایی که View مالک آنها نیست ایجاد می‌کند. Binding ارجاعی به State (یا منبع حقیقت دیگر) است که به View فرزند اجازه می‌دهد مقدار ذخیره شده در والد را بخواند و تغییر دهد. Binding با پیشوند $ نشان داده می‌شود: $count یک Binding<Int> را به View فرزند منتقل می‌کند. بدون Binding، View فرزند نمی‌تواند داده‌های والد را تغییر دهد — فقط می‌تواند آنها را بخواند.

swift
import SwiftUI

struct StepperControl: View {
    @Binding var value: Int
    let range: ClosedRange<Int>
    
    var body: some View {
        HStack {
            Button(action: { if value > range.lowerBound { value -= 1 } }) {
                Image(systemName: "minus.circle")
            }
            Text("\(value)")
                .frame(minWidth: 40)
            Button(action: { if value < range.upperBound { value += 1 } }) {
                Image(systemName: "plus.circle")
            }
        }
    }
}

struct ParentView: View {
    @State private var quantity = 5
    
    var body: some View {
        StepperControl(value: $quantity, range: 1...10)
    }
}

ParentView مالک State quantity است و Binding را از طریق $quantity منتقل می‌کند. StepperControl می‌تواند value را تغییر دهد و quantity در والد به‌طور خودکار همگام‌سازی می‌شود. Binding یک کپی از داده نیست، بلکه پلی به منبع حقیقت است. برای کنترل‌های سفارشی، ویرایشگرها و کامپوننت‌های قابل استفاده مجدد که باید داده‌های والد را تغییر دهند، از @Binding استفاده کنید.

@ObservedObject و @StateObject: مدل‌های داده خارجی

@StateObject — property wrapper برای ایجاد و مالکیت نمونه‌ای از کلاس مطابق با ObservableObject. View یک بار در طول چرخه حیات خود شیء را ایجاد می‌کند و با تغییر خصوصیات @Published آن دوباره ترسیم می‌شود. @ObservedObject — wrapper مشابه، اما View مالک شیء نیست — شیء در خارج از View ایجاد و ذخیره می‌شود (از طریق مقداردهنده اولیه منتقل می‌شود). اپل @StateObject را برای source of truth در سلسله‌مراتب View و @ObservedObject را برای تزریق وابستگی‌ها توصیه می‌کند.

swift
import SwiftUI
import Combine

class UserSettings: ObservableObject {
    @Published var username: String = "Guest"
    @Published var isLoggedIn = false
}

struct ProfileView: View {
    @StateObject private var settings = UserSettings()
    
    var body: some View {
        VStack {
            TextField("Username", text: $settings.username)
                .textFieldStyle(.roundedBorder)
            
            Toggle("Logged In", isOn: $settings.isLoggedIn)
            
            if settings.isLoggedIn {
                Text("خوش آمدید، \(settings.username)!")
                    .font(.headline)
            }
        }
        .padding()
    }
}

UserSettings — ObservableObject با دو خصوصیت @Published. ProfileView از طریق @StateObject مالک شیء است. تغییر username یا isLoggedIn به‌طور خودکار ProfileView را دوباره ترسیم می‌کند. @Published از Combine Publisher برای اطلاع‌رسانی SwiftUI درباره تغییرات استفاده می‌کند. برای انتقال settings به Viewهای فرزند از @ObservedObject استفاده کنید:

Data Flow در SwiftUI: تصویر کامل

اپل چهار سطح Data Flow را در SwiftUI تعریف می‌کند: @State (محلی، value type)، @Binding (دوطرفه)، @StateObject/@ObservedObject (reference type با ObservableObject)، @EnvironmentObject (سراسری، تزریق از طریق محیط). EnvironmentObject امکان انتقال داده از طریق کل سلسله‌مراتب View را بدون انتقال صریح در مقداردهنده اولیه فراهم می‌کند. علاوه بر این @AppStorage با UserDefaults کار می‌کند، @SceneStorage — با وضعیت صحنه، @FetchRequest — با Core Data. انتخاب سطح Data Flow معماری برنامه را تعیین می‌کند: صفحه‌های ساده از State/Binding، ماژولار — ObservedObject، مقیاس بزرگ — EnvironmentObject + راه‌حل‌های شبیه Redux (TCA، Composable Architecture) استفاده می‌کنند.

Property Wrapperمالکیتنوعکی استفاده کنیم
@StateمحلیValue (struct, enum)وضعیت ساده یک View (شمارنده، toggle، فیلد متن)
@Bindingخارجیارجاع به StateView فرزند که داده‌های والد را تغییر می‌دهد
@StateObjectمالکیت ViewReference (class)منبع حقیقت برای مدل داده پیچیده
@ObservedObjectتزریقReference (class)مدل ساخته شده خارج از View (از طریق init منتقل شده)
@EnvironmentObjectسراسریReference (class)داده‌های قابل دسترس برای کل سلسله‌مراتب (احراز هویت، تم)

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

@State چه تفاوتی با @StateObject دارد؟

@State — برای value types (struct, enum, String, Int) و وضعیت محلی یک View. SwiftUI حافظه State را به‌طور خودکار مدیریت می‌کند. @StateObject — برای reference types (class) مطابق با ObservableObject. @StateObject مالک شیء است و View را با تغییر خصوصیات @Published دوباره ترسیم می‌کند. برای شمارنده‌های ساده از @State استفاده کنید؛ برای مدل‌های با منطق — @StateObject.

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

بله، SwiftUI با UIKit از طریق UIHostingController (SwiftUI درون UIKit) و UIViewRepresentable (UIKit درون SwiftUI) یکپارچه می‌شود. UIHostingController SwiftUI View را در UIViewController می‌پیچد. UIViewRepresentable امکان استفاده از کامپوننت‌های UIKit (MKMapView، WKWebView) را در SwiftUI فراهم می‌کند. این رویکرد استاندارد برای مهاجرت پروژه‌ها از UIKit به SwiftUI است.

ViewBuilder در SwiftUI چیست؟

ViewBuilder — result builder (Swift 5.1) که مجموعه‌ای از View را به یک مقدار از نوع TupleView، Group یا ConditionalContent تبدیل می‌کند. ViewBuilder امکان نوشتن if/else و switch امری درون body اعلامی را فراهم می‌کند. بدون ViewBuilder باید برای هر بلوک شرطی AnyView یا Group برگردانده می‌شد. ViewBuilder دلیلی است که در body بین Viewها به کاما نیاز نیست.

آیا SwiftUI روی تمام دستگاه‌های اپل کار می‌کند؟

بله، SwiftUI از iOS 13+، iPadOS 13+، macOS 10.15+، watchOS 6+، tvOS 13+ و visionOS 1+ پشتیبانی می‌کند. با این حال برخی APIها فقط در نسخه‌های جدید در دسترس هستند: برای مثال navigationStack (iOS 16+)، Observable macro (iOS 17+). برای سازگاری معکوس از #available و تطبیق‌های UIKit استفاده کنید.

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

Xcode Debug View Hierarchy درخت SwiftUI View را با modifierها و فریم‌ها نشان می‌دهد. ابزار SwiftUI Inspector (پنل راست Xcode) امکان تغییر modifierها در زمان واقعی را فراهم می‌کند. self._printChanges() در body دلایل ترسیم مجدد را لاگ می‌کند. Instruments با قالب SwiftUI عملکرد View را ردیابی و ترسیم‌های مجدد اضافی را شناسایی می‌کند.

خلاصه

  • SwiftUI — فریم‌ورک اعلامی اپل برای UI، که در آن رابط با ساختارهای View با computed property body توصیف می‌شود (2019).
  • View — value type (struct) مطابق با پروتکل View؛ body از طریق ViewBuilder some View را برمی‌گرداند.
  • @State — وضعیت محلی برای value types؛ با تغییر آن View به‌طور خودکار دوباره ترسیم می‌شود.
  • @Binding — ارتباط دوطرفه از طریق پیشوند $؛ View فرزند داده‌های والد را تغییر می‌دهد.
  • @StateObject / @ObservedObject — reference types با ObservableObject و خصوصیات @Published؛ StateObject مالک شیء است، ObservedObject از خارج دریافت می‌کند.
  • @EnvironmentObject — وضعیت سراسری برای کل سلسله‌مراتب View؛ از طریق .environmentObject() تزریق می‌شود.
  • Data Flow در SwiftUI — از State (محلی) از طریق Binding (دوطرفه) به ObservedObject (ماژولار) و EnvironmentObject (سراسری).

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

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

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

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