ویژگی‌های Swift در توسعه موبایل: چیست، قابلیت‌های کلیدی و نحوه کار

نویسنده: IT Sectr منتشر شده: 2026-06-25 زمان مطالعه: 17 دقیقه

Swift زبان برنامه‌نویسی اپل است که قدرت Objective-C را با امنیت زبان‌های مدرن ترکیب می‌کند. برخلاف بسیاری از زبان‌های دیگر، Swift ساختارهای منحصربه‌فردی ارائه می‌دهد: انواع مقدار با کپی خودکار، Actors با ایزوله‌سازی در سطح کامپایلر، Property Wrappers برای استفاده مجدد از منطق ویژگی‌ها و برنامه‌نویسی پروتکل‌محور به عنوان جایگزینی برای وراثت کلاسیک. طبق مستندات Apple Swift، این قابلیت‌ها کد را ایمن‌تر و کارآمدتر می‌کنند.

نکات کلیدی

  • Struct — نوع مقدار، در انتساب کپی می‌شود، از وراثت پشتیبانی نمی‌کند. Class — نوع مرجع، با مرجع منتقل می‌شود، از وراثت و deinit پشتیبانی می‌کند.
  • Actor — نوع مرجع امن برای نخ با ایزوله‌سازی در سطح کامپایلر. کامپایلر از دسترسی همزمان به حالت قابل تغییر از وظایف مختلف جلوگیری می‌کند.
  • Property Wrappers — @Published, @State, @Binding منطق ویژگی‌ها را در SwiftUI و Combine کپسوله می‌کنند و کد تکراری را حذف می‌کنند.
  • Generics امکان نوشتن توابع و ساختارهای امن از نظر نوع بدون وابستگی به نوع خاص را فراهم می‌کنند. برنامه‌نویسی پروتکل‌محور به جای سلسله‌مراتب کلاس از extension + protocol استفاده می‌کند.
  • Enum با مقادیر مرتبط — ابزاری قدرتمند برای مدل‌سازی حالت‌ها. هر مورد می‌تواند مجموعه‌ای دلخواه از داده‌های انواع مختلف را ذخیره کند.

Struct vs Class در Swift: انواع مقدار و انواع مرجع

در Swift، struct یک نوع مقدار است، در حالی که class یک نوع مرجع است. این تفاوت اساسی رفتار هنگام انتساب، ارسال به توابع و مدیریت حافظه را تعیین می‌کند. Struct در هر انتساب به طور کامل کپی می‌شود، class با مرجع منتقل می‌شود — فقط اشاره‌گر به شیء روی heap کپی می‌شود.

معناشناسی مقدار Struct

Struct به طور خودکار معناشناسی مقدار را پیاده‌سازی می‌کند — هر نمونه مستقل است. تغییر ویژگی struct فقط از طریق var امکان‌پذیر است و روش‌هایی که ویژگی‌ها را تغییر می‌دهند باید mutating علامت‌گذاری شوند. Struct از وراثت پشتیبانی نمی‌کند اما می‌تواند از پروتکل‌ها تبعیت کند. کتابخانه استاندارد Swift از struct برای String, Array, Dictionary, Int, Bool استفاده می‌کند — همه انواع اساسی انواع مقدار هستند.

swift
struct User {
    let id: Int
    var name: String

    mutating func updateName(_ newName: String) {
        name = newName
    }
}

var user1 = User(id: 1, name: "Alice")
var user2 = user1
user2.updateName("Bob")
// user1.name === "Alice", user2.name === "Bob"
// کپی کامل — نمونه‌های مستقل

معناشناسی مرجع Class

Class در heap ذخیره می‌شود و از برابری مرجع پشتیبانی می‌کند. چندین متغیر می‌توانند به یک شیء ارجاع دهند، تغییرات از طریق یک مرجع در همه مراجع دیگر قابل مشاهده است. Class از وراثت پشتیبانی می‌کند، امکان بازنویسی روش (override) را فراهم می‌کند، برای پاک‌سازی منابع deinit دارد. در Swift، class کمتر از struct استفاده می‌شود — اپل توصیه می‌کند با struct شروع کنید و فقط زمانی که وراثت یا معناشناسی مرجع نیاز است به class تغییر دهید.

swift
class Car {
    let model: String
    var speed: Int

    init(model: String, speed: Int) {
        self.model = model
        self.speed = speed
    }

    func accelerate(_ amount: Int) {
        speed += amount
    }
}

let car1 = Car(model: "Tesla", speed: 0)
let car2 = car1
car2.accelerate(50)
// car1.speed === 50, car2.speed === 50
// مرجع یکسان — تغییرات در همه جا قابل مشاهده است

انتخاب بین struct و class به معناشناسی داده بستگی دارد. برای پیکربندی‌ها، مدل‌های داده و حالت‌ها از struct استفاده کنید — کپی کردن ایمن‌تر و قابل پیش‌بینی‌تر است. برای اشیاء با هویت (نشست کاربر، اتصال پایگاه داده) و زمانی که وراثت نیاز است، از class استفاده کنید.

Actor — امنیت نخ در Swift

Actor یک نوع مرجع است که حالت قابل تغییر خود را از دسترسی همزمان محافظت می‌کند. کامپایلر Swift تضمین می‌کند که متغیرهای actor فقط از همان زمینه actor قابل دسترسی هستند — هر دسترسی خارجی باعث خطای کامپایل می‌شود. این کار از رقابت داده در سطح زبان، بدون قفل‌های دستی جلوگیری می‌کند.

ایزوله‌سازی Actor

همه ویژگی‌ها و روش‌های actor به طور پیش‌فرض ایزوله شده‌اند. فراخوانی یک روش actor از خارج نیاز به await دارد — Swift اجرا را به actor تغییر می‌دهد و برمی‌گرداند. Actor دسترسی را به صورت ترتیبی همگام‌سازی می‌کند: درخواست‌های وظایف مختلف در صف قرار می‌گیرند. این امر حالت سازگار در داخل actor را تضمین می‌کند. روش‌های غیرایزوله (nonisolated) را می‌توان بدون await فراخوانی کرد اما نمی‌توانند به ویژگی‌های قابل تغییر دسترسی داشته باشند.

swift
actor BankAccount {
    private var balance: Double

    init(initialBalance: Double) {
        balance = initialBalance
    }

    func deposit(amount: Double) {
        balance += amount
    }

    func withdraw(amount: Double) throws {
        guard balance >= amount else {
            throw BankError.insufficientFunds
        }
        balance -= amount
    }

    nonisolated func accountInfo() -> String {
        return "حساب بانکی"
    }
}

let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — اتمی، بدون شرایط رقابتی

Actor برای مدیران حالت، کش‌ها و خدمات شبکه مفید است جایی که چندین وظیفه به طور همزمان داده می‌خوانند و می‌نویسند. برخلاف همگام‌سازی دستی از طریق NSLock یا DispatchQueue، actor در زمان کامپایل بررسی می‌شود — اشتباه کردن غیرممکن است. خطاهای ایزوله‌سازی در زمان کامپایل ظاهر می‌شوند، نه در زمان اجرا.

Property Wrappers: @Published, @State, @Binding

Property Wrapper یک حاشیه‌نویسی است که بدون تغییر اعلان ویژگی، رفتاری به آن اضافه می‌کند. SwiftUI و Combine لفافه‌های داخلی برای مدیریت حالت نماها فراهم می‌کنند. کامپایلر کدی تولید می‌کند که دسترسی به ویژگی را می‌پیچد و منطق مشاهده، همگام‌سازی یا تبدیل را اضافه می‌کند.

@Published و @State

@Published در کلاس‌های تبعیت‌کننده از ObservableObject برای انتشار خودکار تغییرات استفاده می‌شود. مشترکین Combine در هر به‌روزرسانی اعلان دریافت می‌کنند. @State حالت محلی نمای SwiftUI است. SwiftUI با تغییر @State به طور خودکار نما را دوباره ترسیم می‌کند. @Binding یک ارتباط دوطرفه بین نمای والد و فرزند بدون داشتن داده ایجاد می‌کند.

swift
import SwiftUI
import Combine

@main
struct CounterApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class CounterViewModel: ObservableObject {
    @Published var count: Int = 0

    func increment() {
        count += 1
    }
}

struct ContentView: View {
    @State private var greeting: String = "سلام"
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        VStack {
            CounterDisplay(count: $viewModel.count)
            Text(greeting)
            Button("افزایش", action: viewModel.increment)
        }
    }
}

struct CounterDisplay: View {
    @Binding var count: Int

    var body: some View {
        Text("شمارش: \(count)")
    }
}

Property Wrappers سفارشی با استفاده از @propertyWrapper و ساختاری با فیلد wrappedValue ایجاد می‌شود. این امکان استفاده مجدد از منطق را فراهم می‌کند: اعتبارسنجی، نرمال‌سازی، ذخیره‌سازی UserDefaults. Property Wrappers کد تکراری را به طور قابل توجهی کاهش می‌دهند و هدف توسعه‌دهنده را از طریق حاشیه‌نویسی آشکار می‌کنند.

swift
@propertyWrapper
struct Clamped<T: Comparable> {
    private var value: T
    let range: ClosedRange<T>

    init(wrappedValue: T, range: ClosedRange<T>) {
        self.range = range
        self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
    }

    var wrappedValue: T {
        get { value }
        set { value = min(max(newValue, range.lowerBound), range.upperBound) }
    }
}

struct Settings {
    @Clamped(range: 0...100) var volume: Int = 50
}

var s = Settings()
s.volume = 150
// s.volume === 100 — مقدار به طور خودکار محدود شد

Generics و برنامه‌نویسی پروتکل‌محور

Generics مکانیزم قدرتمند Swift برای نوشتن کد انعطاف‌پذیر بدون از دست دادن امنیت نوع است. توابع و انواع عمومی با هر نوعی که محدودیت‌ها را برآورده کند کار می‌کنند. برنامه‌نویسی پروتکل‌محور (POP) پارادایمی در Swift است که در آن protocol + extension جایگزین وراثت کلاسیک کلاس‌ها می‌شوند و ترکیب رفتار را فراهم می‌کنند.

محدودیت‌های عمومی و انواع مرتبط

Swift اجازه محدود کردن پارامترهای عمومی با پروتکل‌ها (بندهای where) را می‌دهد. پروتکل با نوع مرتبط معادل عمومی برای پروتکل‌ها است: نوع مشخص در زمان تبعیت تعیین می‌شود. این پایه‌ای برای مجموعه‌ها و الگوریتم‌های امن از نظر نوع است. کتابخانه استاندارد Swift فعالانه از Generics استفاده می‌کند: Array, Dictionary, Optional — همه انواع عمومی هستند.

swift
protocol Cacheable {
    associatedtype Key: Hashable
    associatedtype Value

    func get(_ key: Key) -> Value?
    mutating func set(_ value: Value, for key: Key)
}

struct MemoryCache<K: Hashable, V>: Cacheable {
    private var storage: [K: V] = [:]

    typealias Key = K
    typealias Value = V

    func get(_ key: K) -> V? {
        return storage[key]
    }

    mutating func set(_ value: V, for key: K) {
        storage[key] = value
    }
}

func firstMatch<T: Equatable>(in array: [T], target: T) -> Int? {
    for (index, item) in array.enumerated() {
        if item == target {
            return index
        }
    }
    return nil
}

let numbers = [10, 20, 30, 40]
let index = firstMatch(in: numbers, target: 30)
// index === 2 — یک روش عمومی برای همه انواع Equatable

Extension پروتکل و پیاده‌سازی‌های پیش‌فرض

Extension پروتکل یک مکانیزم کلیدی POP است. در extension می‌توان پیاده‌سازی پیش‌فرض روش‌های پروتکل را ارائه داد. انواع تبعیت‌کننده از پروتکل این پیاده‌سازی را رایگان دریافت می‌کنند و در صورت نیاز می‌توانند آن را بازنویسی کنند. این امکان ساخت سلسله‌مراتب رفتار بدون وراثت کلاس را فراهم می‌کند — جایگزینی برای وراثت چندگانه که در Swift وجود ندارد.

swift
protocol Drivable {
    var speed: Double { get set }
    func drive()
}

extension Drivable {
    func drive() {
        if speed > 0 {
            print("رانندگی با سرعت \(speed) کیلومتر/ساعت")
        }
    }
}

struct Bicycle: Drivable {
    var speed: Double = 15
}

struct Plane: Drivable {
    var speed: Double = 900

    func drive() {
        print("پرواز با سرعت \(speed) کیلومتر/ساعت")
    }
}

let bike = Bicycle()
bike.drive() // "رانندگی با سرعت 15.0 کیلومتر/ساعت" — پیش‌فرض

let plane = Plane()
plane.drive() // "پرواز با سرعت 900.0 کیلومتر/ساعت" — بازنویسی شد

POP با extension امکان ترکیب از طریق چندین پروتکل را فراهم می‌کند — یک نوع می‌تواند از چندین پروتکل تبعیت کند و پیاده‌سازی‌های آنها را دریافت کند. این از وراثت تکی کلاس که کل سلسله‌مراتب در آن ثابت است، انعطاف‌پذیرتر است. کتابخانه استاندارد Swift بر روی POP ساخته شده است: CustomStringConvertible, Equatable, Hashable, Codable — همه پروتکل‌هایی با extension هستند.

Enum با مقادیر مرتبط و Extension

Enum در Swift ساختاری به مراتب قدرتمندتر از زبان‌های دیگر است. هر مورد می‌تواند مقادیر مرتبط داشته باشد — مجموعه‌ای دلخواه از داده‌های هر نوع. در ترکیب با extension و تطبیق الگو، enum به پایه‌ای برای مدل‌سازی حالت‌ها، نتایج عملیات و ماشین‌های حالت محدود تبدیل می‌شود.

مقادیر مرتبط و تطبیق الگو

مقادیر مرتبط به هر مورد اجازه ذخیره داده‌های منحصربه‌فرد را می‌دهند. به عنوان مثال، مورد loading داده‌ای ندارد، success شامل نتیجه است، failure شامل خطا است. تطبیق الگو از طریق switch مقادیر مرتبط را استخراج می‌کند و هر مورد را پردازش می‌کند. کامپایلر جامعیت را بررسی می‌کند (exhaustive switch) — این حالت‌های فراموش شده را حذف می‌کند.

swift
enum NetworkResult<T> {
    case loading
    case success(T)
    case failure(Error)
}

enum MediaFile {
    case image(url: URL, width: Int, height: Int)
    case video(url: URL, duration: Double)
    case audio(url: URL, bitrate: Int)
}

func handle(_ result: NetworkResult<String>) {
    switch result {
    case .loading:
        print("در حال بارگیری...")
    case .success(let data):
        print("دریافت شد: \(data)")
    case .failure(let error):
        print("خطا: \(error.localizedDescription)")
    }
}

let file = MediaFile.video(url: URL(string: "https://example.com/video.mp4")!, duration: 120)

if case .video(let url, let duration) = file {
    print("ویدیو \(url) مدت \(duration) ثانیه")
}

Extension برای Enum

Swift اجازه افزودن روش‌ها، ویژگی‌های محاسبه‌شده و تبعیت از پروتکل‌ها را از طریق extension برای enum می‌دهد. این کار نیاز به تغییر اعلان اصلی ندارد — کد تمیز و ماژولار باقی می‌ماند. روش‌های موجود در extension می‌توانند با مقادیر مرتبط کار کنند، داده‌های مشتق شده را محاسبه کنند و منطق تجاری را پیاده‌سازی کنند.

swift
extension MediaFile {
    var fileName: String {
        switch self {
        case .image(let url, _, _),
             .video(let url, _),
             .audio(let url, _):
            return url.lastPathComponent
        }
    }

    var description: String {
        switch self {
        case .image(_, let w, let h):
            return "تصویر \(w)x\(h)"
        case .video(_, let d):
            return "ویدیو \(d)ث"
        case .audio(_, let b):
            return "صدا \(b) kbps"
        }
    }
}

extension MediaFile: Equatable {
    static func == (lhs: MediaFile, rhs: MediaFile) -> Bool {
        return lhs.fileName == rhs.fileName
    }
}

let files: [MediaFile] = [file]
files.forEach { print($0.description) }
// "ویدیو 120.0s"

Enum با مقادیر مرتبط + extension جایگزین کلاس‌های مهروموم از Kotlin یا اتحادیه‌های متمایز از زبان‌های دیگر است. Swift از این ترکیب برای Result (یک نوع استاندارد در کتابخانه استاندارد)، Optional (Optional یک enum با .none و .some است) و مدیریت حالت در SwiftUI استفاده می‌کند. تطبیق الگو تضمین می‌کند که همه حالت‌ها پردازش شده‌اند — خطاهای زمان اجرا غیرممکن هستند.

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

تفاوت struct با class در Swift چیست؟

Struct — نوع مقدار، در انتساب کپی می‌شود، از وراثت پشتیبانی نمی‌کند. Class — نوع مرجع، با مرجع منتقل می‌شود، از وراثت، deinit و بررسی هویت (===) پشتیبانی می‌کند. اپل توصیه می‌کند با struct شروع کنید و فقط زمانی که معناشناسی مرجع نیاز است به class تغییر دهید.

Actor در Swift چیست و چه زمانی استفاده می‌شود؟

Actor — نوع مرجع امن برای نخ. کامپایلر از دسترسی همزمان به حالت قابل تغییر از زمینه‌های مختلف جلوگیری می‌کند. از Actor برای مدیران حالت، کش‌ها و خدماتی که توسط چندین وظیفه قابل دسترسی هستند استفاده کنید. فراخوانی روش‌های actor نیاز به await دارد.

کدام Property Wrappers در SwiftUI استفاده می‌شوند؟

اصلی: @State — حالت محلی نما؛ @Binding — اتصال داده بدون مالکیت؛ @Published — انتشار تغییرات در ObservableObject؛ @StateObject — مالکیت ObservableObject؛ @EnvironmentObject — وابستگی از محیط. لفافه‌های سفارشی از طریق @propertyWrapper ایجاد می‌شوند.

برنامه‌نویسی پروتکل‌محور چیست؟

POP — پارادایمی که در آن protocol + extension به جای وراثت کلاس رفتار را تعریف می‌کنند. یک نوع از چندین پروتکل تبعیت می‌کند و پیاده‌سازی‌های آنها را رایگان دریافت می‌کند. این ترکیب به جای وراثت است — انعطاف‌پذیرتر و ایمن‌تر. کتابخانه استاندارد Swift (Equatable, Codable) بر روی POP ساخته شده است.

enum در Swift چه تفاوتی با enum در زبان‌های دیگر دارد؟

enum در Swift از مقادیر مرتبط پشتیبانی می‌کند — هر مورد می‌تواند داده‌های دلخواه از انواع مختلف را ذخیره کند. در ترکیب با تطبیق الگو (switch)، این مدل قدرتمندی برای حالت‌ها، خطاها و طراحی مبتنی بر دامنه فراهم می‌کند. Optional و Result enumهای استاندارد Swift با مقادیر مرتبط هستند.

خلاصه

  • Struct vs Class — تفاوت اساسی: انواع مقدار کپی می‌شوند، انواع مرجع با مرجع منتقل می‌شوند. Struct از وراثت پشتیبانی نمی‌کند، class پشتیبانی می‌کند. اپل به طور پیش‌فرض struct را توصیه می‌کند.
  • Actor — امنیت نخ در سطح کامپایلر. حالت قابل تغییر ایزوله، دسترسی از طریق await، محافظت در برابر رقابت داده بدون قفل‌های دستی.
  • Property Wrappers — @Published, @State, @Binding و سفارشی از طریق @propertyWrapper. کد تکراری را کاهش می‌دهند و هدف را از طریق حاشیه‌نویسی آشکار می‌کنند.
  • Generics — توابع و انواع امن از نظر نوع با محدودیت‌های where. Protocol + نوع مرتبط برای انتزاع. کتابخانه استاندارد Swift کاملاً بر روی Generics ساخته شده است.
  • برنامه‌نویسی پروتکل‌محور — ترکیب رفتار از طریق extension پروتکل. پیاده‌سازی‌های پیش‌فرض امکان استفاده مجدد از کد را بدون وراثت کلاس فراهم می‌کنند.
  • Enum با مقادیر مرتبط — مدل قدرتمند برای حالت‌ها. هر مورد داده‌های منحصربه‌فرد ذخیره می‌کند. تطبیق الگو تضمین می‌کند همه حالت‌ها پردازش شوند.
  • Extension — روش‌ها، ویژگی‌های محاسبه‌شده و تبعیت از پروتکل را برای هر نوع از جمله enum اضافه می‌کند. کد بدون تغییر اعلان اصلی ماژولار و تمیز باقی می‌ماند.

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

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

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