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, τελικές κλάσεις με αμετάβλητη κατάσταση και συναρτήσεις/κλείσιματα που σημαιώνονται με @Sendable. Ο μεταγλωτιστής συνάγει αυτόματα τη συμμόρφωση με το Sendable για τους τύπους τιμής.

Τύποι τιμής και αυτόματη συμμόρφωση

Struct, enum και tuple γίνονται αυτόματα Sendable εάν όλες οι ιδιότητές και οι σχετιζόμενες τιμές τους είναι επίσης Sendable. Αυτή είναι μια συντηρητική προσέγγιση: εάν ακόμη και μία ιδιότητα δεν συμμορφώνεται με το Sendable, ο λόκληρος τύπος δεν θα θεωρηθεί ασφαλής.

ΤύποςSendableΠροϋπόθεση
StructΝαι (χωρίς ρητή ένδειξη)Όλες οι ιδιότητες Sendable
EnumΝαι (χωρίς ρητή ένδειξη)Όλες οι σχετιζόμενες τιμές 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 και δεν θα μεταβληθούν από τον εξωτερικό περιβάλλοντα. Για κλάσεις, επιτρέπεται η σύλληψη της ασθενούς αναφοράς weak self εάν η κλάση δεν είναι σημασμένη ως Sendable. Αυτό αποτρέπει τους κλασικούς κύκλους συγκράτησης και τις συνθήκες ανταγωνισμού.

Συχνές Ερωτήσεις

Τι είναι το Sendable στο Swift με απλά λόγια;

Sendable — είναι ένας δείκτης που λέει στον μεταγλωτιστή: “Αυτός ο τύπος μπορεί να μεταφορθεί με ασφάλεια μεταξύ νημάτων”. Οι δομές και οι σταθερές είναι συνήθως Sendable από προκαταβολή, οι κλάσεις — όχι, εκτός εάν δηλωθεί ρητά.

Ποιοι τύποι συμμορφώνονται αυτόματα με το Sendable;

Οι τύποι τιμής (struct, enum) με ιδιότητες Sendable, οι τελικές κλάσεις με αμετάβλητη κατάσταση, καθώς και όλοι οι βασικοί τύποι Swift: Int, String, Double, Bool, Array, Dictionary, Optional — συμμορφώνονται αυτόματα με το Sendable.

Τι είναι το @unchecked Sendable;

@unchecked Sendable — είναι μια μέθοδος για να κηρυχθεί μια κλάση ως Sendable χωρίς στατικό έλεγχο από τον μεταγλωτιστή. Ο αναπτυκτής εγγυάται την ασφάλεια αυτόνομα, συχνά μέσω κλειδωμάτων ή ατομικών λειτουργιών.

Γιατί χρειάζεται το Sendable για Actor;

Ο Actor απομονώνει την κατάστασή του, αλλά κατά την επιστροφή δεδομένων σε εξωτερικό κώδικα, αυτά τα δεδομένα διασχίζουν το όριο απομόνωσης. Sendable εγγυάται ότι ο παραλήπτης δεν θα συναντήσει συνθήκες ανταγωνισμού κατά τη χρήση αυτών των δεδομένων εκτός του actor.

Πώς κάνω μια κλάση Sendable στο Swift;

Προσθέστε το πρωτόκολλο Sendable σε μια τελική κλάση της οποίας όλες οι ιδιότητες είναι σταθερές τυπων Sendable. Εάν η κλάση χρησιμοποιεί κλειδώματα, μπορεί να εφαρμοστεί @unchecked Sendable, αλλά αυτό απαιτεί προσοχή.

Σύνοψη

  • Sendable — πρωτόκολλο-δείκτης για ασφαλή μεταφορά δεδομένων μεταξύ νημάτων
  • Οι τύποι τιμής συμμορφώνονται αυτόματα με το Sendable όταν πληρούνται οι προϋποθέσεις
  • Οι κλάσεις απαιτούν ρητή ένδειξη Sendable ή @unchecked Sendable
  • Actor επιστρέφει δεδομένα σε εξωτερικό κώδικα μόνο μέσω τυπων Sendable
  • @Sendable χαρακτηριστικό κλεισίματος ελέγχει την ορθότητα σύλληψης μεταβλητών
  • Μεταγλωτιστής ελέγχει στατικά τη συμμόρφωση με το Sendable, αποτρέποντας τις συνθήκες ανταγωνισμού στη φάση κατασκευής

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης