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