Published on

Swiftda sendable

Authors

Sendable — thread-safe turlar

Sendable — turni bir concurrency domain dan boshqasiga xavfsiz uzatish mumkinligini bildiruvchi protokol. Oddiy qilib aytganda: agar biror qiymatni Task { } ichiga yoki actor ga yuborayotgan bo'lsangiz — u qiymatning turi Sendable bo'lishi kerak. Swift 6 da bu qat'iy tekshiriladi — Sendable bo'lmagan turni Task yoki actor chegarasi orqali uzatish kompilyatsiya xatosi beradi.

Nima uchun kerak? — Agar ikki thread bir xil ob'ektga bir vaqtda kirsa va uni o'zgartirsa — data race paydo bo'ladi. Sendable bu muammoni oldini oladi: faqat xavfsiz turlar uzatilishi mumkin.

Sendable tushunchasi

Value type lar (Int, String, Bool, struct) avtomatik Sendable — chunki ular uzatilganda nusxa olinadi va original o'zgarmaydi. Class lar esa default Sendable emas — chunki reference type: bir nechta thread bir xil ob'ektga kirishi va o'zgartirishi mumkin.

// ═══════════════════════════════════════
//  QAYSI TURLAR SENDABLE?
// ═══════════════════════════════════════

// ✅ Avtomatik Sendable — value typelar
// Int, Double, Bool, String — nusxa oladi, original o'zgarmaydi
let son: Int = 42  // ✅ Sendable

// ✅ Struct — barcha property lari Sendable bo'lsa
struct Nuqta: Sendable {
    let x: Double  // ✅ Double — Sendable
    let y: Double  // ✅ Double — Sendable
}

// ✅ Enum — barcha associated value lari Sendable bo'lsa
enum Natija: Sendable {
    case muvaffaqiyat(String)  // ✅ String — Sendable
    case xato(Int)             // ✅ Int — Sendable
}

// ❌ Class — default Sendable emas
class OddiyClass {
    var qiymat = 0  // var — boshqa thread o'zgartirishi mumkin
}
// OddiyClass() ni Task ga uzatish xavfli — data race!


// ✅ final class — let property lar bilan Sendable
final class XavfsizClass: Sendable {
    let ism: String       // ✅ let — o'zgarmaydi
    let yosh: Int         // ✅ let — o'zgarmaydi
    // var qo'yib bo'lmaydi! Sendable buziladi

    init(ism: String, yosh: Int) {
        self.ism = ism
        self.yosh = yosh
    }
}

@Sendable closure

@Sendable — closure ning concurrency chegarasini xavfsiz kesib o'tishini bildiradi. Task { } ning closure si avtomatik @Sendable. Bu degani — closure ichida capture qilingan barcha qiymatlar Sendable bo'lishi kerak. var o'zgaruvchini capture qilish xavfli — let ishlatish kerak.

// ═══════════════════════════════════════
//  @SENDABLE CLOSURE
//  Concurrency chegarasini kesib o'tadigan closure
// ═══════════════════════════════════════

// Task init — @Sendable closure qabul qiladi
var tashqariQiymat = 0

Task { // @Sendable closure
    // ❌ tashqariQiymat ni o'zgartirish xavfli
    // Swift 6: kompilyatsiya xatosi
    // tashqariQiymat += 1
}

// ✅ TO'G'RI — Sendable qiymatlar bilan
let xavfsizQiymat = 42  // let — Sendable

Task {
    // ✅ let qiymat — nusxa olinadi, xavfsiz
    print(xavfsizQiymat)
}


// @Sendable funksiya parametr sifatida
func fonDaBajar(ish: @Sendable () -> Void) {
    Task {
        ish()
    }
}

// Ishlatish
let ism = "Ali"  // let — Sendable
fonDaBajar {
    print("Salom, \(ism)!")  // ✅ let capture — xavfsiz
}

@Unchecked sendable

Ba'zan class ni Sendable qilish kerak, lekin var property lar bor. Bunday hollarda @unchecked Sendable ishlatiladi — bu compiler ga "men o'zim thread-safety ni ta'minlayman" degan ma'noni beradi. Compiler tekshirmaydi — javobgarlik to'liq dasturchida. Odatda NSLock, DispatchQueue yoki boshqa sinxronizatsiya mexanizmlari bilan himoyalanadi.

// ═══════════════════════════════════════
//  @UNCHECKED SENDABLE
//  "Men o'zim thread-safety ni kafolatlayaman"
//  Compiler tekshirmaydi — javobgarlik sizda!
// ═══════════════════════════════════════
final class ThreadXavfsizKesh: @unchecked Sendable {
    private let lock = NSLock()  // Qo'lda qulflash
    private var saqlangan: [String: Any] = [:]

    func saqlash(kalit: String, qiymat: Any) {
        lock.lock()
        defer { lock.unlock() }
        saqlangan[kalit] = qiymat
    }

    func olish(kalit: String) -> Any? {
        lock.lock()
        defer { lock.unlock() }
        return saqlangan[kalit]
    }
}

// ✅ Xavfsiz — lock bilan himoyalangan
// Lekin compiler buni bilmaydi — @unchecked ishonadi

// OGOHLANTRISH: @unchecked ni faqat haqiqatan
// thread-safe qilganingizda ishlating!
// Aks holda — data race va crash

Sendable tekshiruvi amalda

Swift 6 da Sendable tekshiruvi qat'iy. Quyida non-Sendable turni Task ga uzatishning muammosi va uchta yechimi ko'rsatilgan: struct ishlatish, actor ishlatish yoki final class + let ishlatish.

// ═══════════════════════════════════════
//  SWIFT 6 DA STRICT CHECKING
// ═══════════════════════════════════════

// ❌ Kompilyatsiya xatosi — non-Sendable turni Task ga uzatish
class Foydalanuvchi {
    var ism = "Ali"  // var — xavfli
}

let user = Foydalanuvchi()

Task {
    // ❌ Swift 6: "Capture of 'user' with non-Sendable type
    //    'Foydalanuvchi' in @Sendable closure"
    // print(user.ism)
}


// ✅ Yechimlar:
// 1. struct ishlatish
struct FoydalanuvchiXavfsiz: Sendable {
    let ism: String
}

// 2. actor ishlatish
actor FoydalanuvchiActor {
    var ism = "Ali"
}

// 3. final class + let
final class FoydalanuvchiFinal: Sendable {
    let ism: String
    init(ism: String) { self.ism = ism }
}

Qoidalar jadvali

TurSendable?Shart
Int, String, Bool✅ HaHar doim
struct✅ HaBarcha property Sendable
enum✅ HaBarcha associated value Sendable
actor✅ HaHar doim — izolyatsiya kafolat
final class⚠️ ShartliBarcha stored property let va Sendable
class❌ Yo'q@unchecked bilan qo'lda
Closure⚠️ Shartli@Sendable belgilanishi kerak

🎯 Topshiriq

Buyurtma struct yarating (barcha property lar Sendable). BuyurtmaMenejeri actor yarating. 10 ta parallel Task dan buyurtma qo'shing. Keyin final class KeshMenejer: @unchecked Sendable yarating — NSLock bilan himoyalang. Ikkalasini solishtiring.

Buy mea coffee