Sendable — این چیست، پروتکل ایمنی رشته

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

Sendable — این یک پروتکل Swift است که تیپ‌هایی را که برای انتقال بین رشته‌ها ایمن هستند، علامت‌گذاری می‌کند. هنگام کار با همزمانی (actor, async/await, Task)، کامپایلر Swift نیاز دارد که همه داده‌هایی که بین کنتکست‌های جداگانه انتقال می‌یابند، با Sendable مطابقت داشته باشند. این انتقال تصادفی تیپ‌های ناامنی را که می‌توانند به مسابقه داده‌ها منجر شوند، مرتفع می‌کند. پروتکل به عنوان یک قرارداد عمل می‌کند: تیپی که با Sendable مطابقت دارد، ضمانت می‌دهد که وضعیت داخلی همگام‌سازی‌نشده‌ای ندارد. به گزارش WWDC 2021، پروتکل Sendable یک عنصر اجباری در طراحی معماری ایمن چندرشته‌ای است.

نکات کلیدی

  • Sendable — پروتکلی که ضمانت می‌دهد در انتقال بین رشته‌ها مسابقه داده‌ها وجود نداشته باشد
  • انواع مقداری (struct, enum) اگر تمامی ویژگی‌های آنها Sendable باشند، به‌طور خودکار با Sendable مطابقت دارند
  • @unchecked Sendable — مکانیسم انحرافی برای کلاس‌هایی که توسعه‌دهنده ایمنی آنها را بر عهده می‌گیرد
  • بسته‌های Sendable با ویژگی @Sendable علامت‌گذاری می‌شوند که جذب متغیرها را بررسی می‌کند
  • کامپایلر در صورتی که یک نوع غیر Sendable بین کنتکست‌های جداگانه انتقال یابد، خطا صادر می‌کند

پروتکل Sendable در Swift چیست؟

Sendable — این یک پروتکل از کتابخانه استاندارد Swift (SE-0302) است که تیپ‌های ایمن برای انتقال بین دامنه‌های جداگانه را علامت‌گذاری می‌کند. دامنه جداگانه شامل actor، وظیفه Task یا کنتکست @MainActor است. Sendable هیچ نیازمندی ندارد — آن به عنوان یک نشانگر ایمنی عمل می‌کند.

چرا Sendable نیاز است

قبل از Swift 5.5، توسعه‌دهندگان می‌توانستند هر شیئی را از طریق DispatchQueue بین رشته‌ها انتقال دهند و کامپایلر بررسی نمی‌کرد که آیا این ایمن است یا خیر. Sendable این شکاف را می‌بندد: اکنون کامپایلر خود انتقالات بین‌رشته‌ای را ردیابی می‌کند و انتقالات ناامن را مسدود می‌کند. این کد همزمان را حتی قبل از اجرا بیشتر قابل اعتماد می‌کند.

swift
struct UserProfile: Sendable {
    let name: String
    let age: Int
}

class NonSendableClass {
    var counter: Int = 0
}

در مثال، UserProfile می‌تواند به‌طور ایمن بین رشته‌ها انتقال یابد، زیرا این یک ساختار با ویژگی‌های ثابت از انواع Sendable است. NonSendableClass در صورت انتقال از طریق await یا Task باعث خطای کامپایل خواهد شد.

کدام تیپ‌ها به‌طور پیش‌فرض با Sendable مطابقت دارند

انواع Sendable در Swift به سه دسته تقسیم می‌شوند: انواع مقداری با ویژگی‌های Sendable، کلاس‌های final با وضعیت تغییرناپذیر و توابع/بسته‌هایی که با @Sendable علامت‌گذاری شده‌اند. کامپایلر به‌طور خودکار مطابقت Sendable را برای انواع مقداری استنباط می‌کند.

انواع مقداری و مطابقت خودکار

Struct, enum و tuple اگر تمامی ویژگی‌ها و مقادیر همراه آنها نیز Sendable باشند، به‌طور خودکار Sendable می‌شوند. این یک رویکرد محافظه‌کارانه است: اگر حتی یک ویژگی با Sendable مطابقت نداشته باشد، کل نوع ایمن تلقی نخواهد شد.

نوعSendableشرط
Structبله (بدون ذکر صریح)تمامی ویژگی‌ها Sendable
Enumبله (بدون ذکر صریح)تمامی associated values Sendable
Final classبله (با ذکر صریح)تمامی ویژگی‌های let Sendable، بدون var
Non-final classخیربه دلیل وراثت نمی‌تواند Sendable باشد

انواع پایه

تمامی انواع ساخته شده Swift — Int, String, Double, Bool, Optional, Array, Dictionary, Set — با Sendable مطابقت دارند. این ترکیب انواع را به‌طور پیش‌فرض ایمن می‌کند. توسعه‌دهنده فقط باید مراقب کلاس‌های سفارشی باشد.

Sendable و کلاس‌ها: @unchecked Sendable

@unchecked Sendable — این مکانیسمی است که به یک کلاس اجازه می‌دهد خود را صریحاً Sendable اعلام کند و بررسی‌های کامپایلر را دور بزند. توسعه‌دهنده مسئولیت ایمنی رشته‌ای چنین کلاسی را بر عهده می‌گیرد. این برای پل‌های Objective-C و ساختارهای بهینه‌شده مفید است.

کی از @unchecked Sendable استفاده کنیم

@unchecked Sendable زمانی استفاده می‌شود که کلاس به‌طور داخلی از طریق قفل‌ها یا عملیات اتمی ایمنی را تضمین می‌کند، اما کامپایلر نمی‌تواند این را به‌طور استاتیک بررسی کند. به عنوان مثال، کلاسی با os_unfair_lock یا pthread_mutex_t — ایمنی رشته‌ای آن توسط کد تأمین می‌شود، اما Swift آن را نمی‌بیند.

swift
final class AtomicCounter: @unchecked Sendable {
    private var value: Int = 0
    private let lock = NSLock()
    
    func increment() {
        lock.lock()
        value += 1
        lock.unlock()
    }
}

@unchecked Sendable باید با احتیاط استفاده شود. این یک سیگنال واضح برای سایر توسعه‌دهندگان است: «من بررسی کردم، این ایمن است». خطا در پیاده‌سازی می‌تواند به مسابقه‌های به سختی قابل شناسایی منجر شود. قبل از استفاده از @unchecked، مطمئن شوید که نوع واقعاً نمی‌تواند به عنوان یک نوع مقداری بازنویسی شود.

Sendable در ترکیب با Actor

Actor و Sendable دو طرف یک سکه هستند. Actor وضعیت خود را جدا می‌کند، اما برای تبادل داده با دنیای خارجی باید انواع Sendable را برگرداند. اگر روش actor یک نوع غیر Sendable برگرداند، کامپایلر هشدار یا خطا صادر می‌کند.

انتقال داده‌ها از طریق Sendable

وقتی actor داده‌هایی را به کد خارجی ارسال می‌کند، این داده‌ها از مرز جداگانگی عبور می‌کنند. Sendable ضمانت می‌دهد که دریافت‌کننده می‌تواند آنها را در خارج از actor به‌طور ایمن استفاده کند. خود actor جداگانه باقی می‌ماند — وضعیت داخلی آن فاش نمی‌شود.

swift
struct AccountSnapshot: Sendable {
    let id: UUID
    let balance: Double
    let lastUpdated: Date
}

actor BankActor {
    private var balance: Double = 0
    
    func snapshot() async -> AccountSnapshot {
        return AccountSnapshot(
            id: UUID(),
            balance: balance,
            lastUpdated: Date()
        )
    }
}

AccountSnapshot — این یک ساختار Sendable است که فقط ویژگی‌های let از انواع Sendable را دارد. این رویکرد best practice برای استخراج داده‌ها از actor است. عکس وضعیت به‌صورت مقدار انتقال می‌یابد و actor کنترل خود را بر وضعیتش از دست نمی‌دهد.

توابع و بسته‌های Sendable

@Sendable — این یک ویژگی برای توابع و بسته‌ها است که ضمانت می‌دهد بسته داده‌های غیر Sendable را به صورت تغییرپذیر جذب نمی‌کند. وقتی بسته به Task یا روش actor انتقال می‌یابد، باید Sendable باشد.

بررسی جذب در @Sendable بسته‌ها

کامپایلر بررسی می‌کند که @Sendable بسته ارجاعات قابل تغییر به کلاس‌ها را جذب نمی‌کند. جذب ویژگی‌های let از انواع Sendable مجاز است. جذب متغیر var از نوع ارجاعی منجر به خطا می‌شود، زیرا بسته ممکن است همزمان با تغییر اجرا شود.

swift
func performAsync(operation: @Sendable () -> Void) {
    Task {
        await operation()
    }
}

let constant = "Safe"
var counter = 0
// counter — جذب var کانتر را تغییر می‌دهد، خطای کامپایل
performAsync { // ❌ تغییر var جذب‌شده
    print(constant)
}

قانون ساده است: @Sendable بسته فقط می‌تواند داده‌هایی را جذب کند که خود Sendable هستند و از خارج موتاسیون نخواهند شد. برای کلاس‌ها، اگر کلاس به عنوان Sendable علامت‌گذاری نشده است، جذب ارجاع weak self مجاز است. این از چرخه‌های کلاسیک retain و race condition جلوگیری می‌کند.

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

Sendable در Swift به زبان ساده چیست؟

Sendable — این یک نشانگر است که به کامپایلر می‌گوید: «این نوع را می‌توان به‌طور ایمن بین رشته‌ها انتقال داد». ساختارها و ثابت‌ها معمولاً به‌طور پیش‌فرض Sendable هستند، کلاس‌ها خیر، مگر اینکه صریحاً مشخص شده باشد.

کدام انواعی به‌طور خودکار با Sendable مطابقت دارند؟

انواع مقداری (struct, enum) با ویژگی‌های Sendable، کلاس‌های final با وضعیت تغییرناپذیر، و همچنین تمامی انواع پایه Swift: Int, String, Double, Bool, Array, Dictionary, Optional — به‌طور خودکار با Sendable مطابقت دارند.

@unchecked Sendable چیست؟

@unchecked Sendable — این راهی است برای اعلام کلاس به عنوان Sendable بدون بررسی استاتیک کامپایلر. توسعه‌دهنده ایمنی را خودش تضمین می‌کند، اغلب از طریق قفل‌ها یا عملیات اتمی.

چرا Sendable برای Actor نیاز است؟

Actor وضعیت خود را جدا می‌کند، اما وقتی داده‌ها را به کد خارجی برمی‌گرداند، این داده‌ها از مرز جداگانگی عبور می‌کنند. Sendable ضمانت می‌دهد که دریافت‌کننده در استفاده از این داده‌ها در خارج از actor با مسابقه مواجه نخواهد شد.

چگونه یک کلاس را در Swift Sendable کنیم؟

پروتکل Sendable را به یک کلاس final که تمامی ویژگی‌هایش ثابت‌هایی از انواع Sendable هستند، اضافه کنید. اگر کلاس از قفل‌ها استفاده می‌کند، می‌توان @unchecked Sendable را اعمال کرد، اما این نیازمند احتیاط است.

نتیجه

  • Sendable — پروتکل-نشانگر برای انتقال ایمن داده بین رشته‌ها
  • انواع مقداری در صورت انطباق شرایط به‌طور خودکار با Sendable مطابقت دارند
  • کلاس‌ها نیاز به ذکر صریح Sendable یا @unchecked Sendable دارند
  • Actor داده‌ها را به کد خارجی فقط از طریق انواع Sendable برمی‌گرداند
  • @Sendable ویژگی بسته‌ها درستی جذب متغیرها را بررسی می‌کند
  • کامپایلر به‌طور استاتیک مطابقت Sendable را بررسی می‌کند و از مسابقه در مرحله ساخت جلوگیری می‌کند

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

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

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

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