Swift زبان برنامهنویسی اپل است که قدرت Objective-C را با امنیت زبانهای مدرن ترکیب میکند. برخلاف بسیاری از زبانهای دیگر، Swift ساختارهای منحصربهفردی ارائه میدهد: انواع مقدار با کپی خودکار، Actors با ایزولهسازی در سطح کامپایلر، Property Wrappers برای استفاده مجدد از منطق ویژگیها و برنامهنویسی پروتکلمحور به عنوان جایگزینی برای وراثت کلاسیک. طبق مستندات Apple Swift، این قابلیتها کد را ایمنتر و کارآمدتر میکنند.
نکات کلیدی
در Swift، struct یک نوع مقدار است، در حالی که class یک نوع مرجع است. این تفاوت اساسی رفتار هنگام انتساب، ارسال به توابع و مدیریت حافظه را تعیین میکند. Struct در هر انتساب به طور کامل کپی میشود، class با مرجع منتقل میشود — فقط اشارهگر به شیء روی heap کپی میشود.
Struct به طور خودکار معناشناسی مقدار را پیادهسازی میکند — هر نمونه مستقل است. تغییر ویژگی struct فقط از طریق var امکانپذیر است و روشهایی که ویژگیها را تغییر میدهند باید mutating علامتگذاری شوند. Struct از وراثت پشتیبانی نمیکند اما میتواند از پروتکلها تبعیت کند. کتابخانه استاندارد Swift از struct برای String, Array, Dictionary, Int, Bool استفاده میکند — همه انواع اساسی انواع مقدار هستند.
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 در heap ذخیره میشود و از برابری مرجع پشتیبانی میکند. چندین متغیر میتوانند به یک شیء ارجاع دهند، تغییرات از طریق یک مرجع در همه مراجع دیگر قابل مشاهده است. Class از وراثت پشتیبانی میکند، امکان بازنویسی روش (override) را فراهم میکند، برای پاکسازی منابع deinit دارد. در Swift، class کمتر از struct استفاده میشود — اپل توصیه میکند با struct شروع کنید و فقط زمانی که وراثت یا معناشناسی مرجع نیاز است به class تغییر دهید.
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 فقط از همان زمینه actor قابل دسترسی هستند — هر دسترسی خارجی باعث خطای کامپایل میشود. این کار از رقابت داده در سطح زبان، بدون قفلهای دستی جلوگیری میکند.
همه ویژگیها و روشهای actor به طور پیشفرض ایزوله شدهاند. فراخوانی یک روش actor از خارج نیاز به await دارد — Swift اجرا را به actor تغییر میدهد و برمیگرداند. Actor دسترسی را به صورت ترتیبی همگامسازی میکند: درخواستهای وظایف مختلف در صف قرار میگیرند. این امر حالت سازگار در داخل actor را تضمین میکند. روشهای غیرایزوله (nonisolated) را میتوان بدون await فراخوانی کرد اما نمیتوانند به ویژگیهای قابل تغییر دسترسی داشته باشند.
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 Wrapper یک حاشیهنویسی است که بدون تغییر اعلان ویژگی، رفتاری به آن اضافه میکند. SwiftUI و Combine لفافههای داخلی برای مدیریت حالت نماها فراهم میکنند. کامپایلر کدی تولید میکند که دسترسی به ویژگی را میپیچد و منطق مشاهده، همگامسازی یا تبدیل را اضافه میکند.
@Published در کلاسهای تبعیتکننده از ObservableObject برای انتشار خودکار تغییرات استفاده میشود. مشترکین Combine در هر بهروزرسانی اعلان دریافت میکنند. @State حالت محلی نمای SwiftUI است. SwiftUI با تغییر @State به طور خودکار نما را دوباره ترسیم میکند. @Binding یک ارتباط دوطرفه بین نمای والد و فرزند بدون داشتن داده ایجاد میکند.
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 کد تکراری را به طور قابل توجهی کاهش میدهند و هدف توسعهدهنده را از طریق حاشیهنویسی آشکار میکنند.
@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 مکانیزم قدرتمند Swift برای نوشتن کد انعطافپذیر بدون از دست دادن امنیت نوع است. توابع و انواع عمومی با هر نوعی که محدودیتها را برآورده کند کار میکنند. برنامهنویسی پروتکلمحور (POP) پارادایمی در Swift است که در آن protocol + extension جایگزین وراثت کلاسیک کلاسها میشوند و ترکیب رفتار را فراهم میکنند.
Swift اجازه محدود کردن پارامترهای عمومی با پروتکلها (بندهای where) را میدهد. پروتکل با نوع مرتبط معادل عمومی برای پروتکلها است: نوع مشخص در زمان تبعیت تعیین میشود. این پایهای برای مجموعهها و الگوریتمهای امن از نظر نوع است. کتابخانه استاندارد Swift فعالانه از Generics استفاده میکند: Array, Dictionary, Optional — همه انواع عمومی هستند.
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 پروتکل یک مکانیزم کلیدی POP است. در extension میتوان پیادهسازی پیشفرض روشهای پروتکل را ارائه داد. انواع تبعیتکننده از پروتکل این پیادهسازی را رایگان دریافت میکنند و در صورت نیاز میتوانند آن را بازنویسی کنند. این امکان ساخت سلسلهمراتب رفتار بدون وراثت کلاس را فراهم میکند — جایگزینی برای وراثت چندگانه که در 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 در Swift ساختاری به مراتب قدرتمندتر از زبانهای دیگر است. هر مورد میتواند مقادیر مرتبط داشته باشد — مجموعهای دلخواه از دادههای هر نوع. در ترکیب با extension و تطبیق الگو، enum به پایهای برای مدلسازی حالتها، نتایج عملیات و ماشینهای حالت محدود تبدیل میشود.
مقادیر مرتبط به هر مورد اجازه ذخیره دادههای منحصربهفرد را میدهند. به عنوان مثال، مورد loading دادهای ندارد، success شامل نتیجه است، failure شامل خطا است. تطبیق الگو از طریق switch مقادیر مرتبط را استخراج میکند و هر مورد را پردازش میکند. کامپایلر جامعیت را بررسی میکند (exhaustive switch) — این حالتهای فراموش شده را حذف میکند.
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) ثانیه")
}
Swift اجازه افزودن روشها، ویژگیهای محاسبهشده و تبعیت از پروتکلها را از طریق extension برای enum میدهد. این کار نیاز به تغییر اعلان اصلی ندارد — کد تمیز و ماژولار باقی میماند. روشهای موجود در extension میتوانند با مقادیر مرتبط کار کنند، دادههای مشتق شده را محاسبه کنند و منطق تجاری را پیادهسازی کنند.
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 — نوع مرجع، با مرجع منتقل میشود، از وراثت، deinit و بررسی هویت (===) پشتیبانی میکند. اپل توصیه میکند با struct شروع کنید و فقط زمانی که معناشناسی مرجع نیاز است به class تغییر دهید.
Actor — نوع مرجع امن برای نخ. کامپایلر از دسترسی همزمان به حالت قابل تغییر از زمینههای مختلف جلوگیری میکند. از Actor برای مدیران حالت، کشها و خدماتی که توسط چندین وظیفه قابل دسترسی هستند استفاده کنید. فراخوانی روشهای actor نیاز به await دارد.
اصلی: @State — حالت محلی نما؛ @Binding — اتصال داده بدون مالکیت؛ @Published — انتشار تغییرات در ObservableObject؛ @StateObject — مالکیت ObservableObject؛ @EnvironmentObject — وابستگی از محیط. لفافههای سفارشی از طریق @propertyWrapper ایجاد میشوند.
POP — پارادایمی که در آن protocol + extension به جای وراثت کلاس رفتار را تعریف میکنند. یک نوع از چندین پروتکل تبعیت میکند و پیادهسازیهای آنها را رایگان دریافت میکند. این ترکیب به جای وراثت است — انعطافپذیرتر و ایمنتر. کتابخانه استاندارد Swift (Equatable, Codable) بر روی POP ساخته شده است.
enum در Swift از مقادیر مرتبط پشتیبانی میکند — هر مورد میتواند دادههای دلخواه از انواع مختلف را ذخیره کند. در ترکیب با تطبیق الگو (switch)، این مدل قدرتمندی برای حالتها، خطاها و طراحی مبتنی بر دامنه فراهم میکند. Optional و Result enumهای استاندارد Swift با مقادیر مرتبط هستند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.