Τι σημαίνει @escaping και @nonescaping κλεισίματα στο Swift;

Κατά τη διάρκεια του κώδικα, κάθε φορά που εργάζεστε με τις λειτουργίες, μπορεί να έχετε τρέξει με τα χαρακτηριστικά @escaping ή @nonescaping. Έχετε δώσει ποτέ το χρόνο να σκεφτεί για, τι σημαίνει; Έτσι, εδώ, πρόκειται να συζητήσουν σχετικά με αυτούς τους όρους.

Τι είναι τα κλεισίματα;

Τα κλείνουν είναι αυτοτελείς μπλοκ λειτουργικότητας που μπορούν να μεταφερθούν και να χρησιμοποιηθούν στον κώδικα σας.

Στις παραμέτρους Swift 1.x και Swift 2.x, η παράμετρος κλεισίματος ήταν @less από προεπιλογή, σημαίνει ότι το κλείσιμο μπορεί να διαφύγει κατά την εκτέλεση της λειτουργίας του σώματος. αν δεν θέλετε να ξεφύγετε από τις παραμέτρους κλεισίματος, επισημάνετε την ως @nonecaping.

Σε Swift 3.x, η Apple έκανε μια αλλαγή: οι παράμετροι κλεισίματος έγιναν @noncapcaping από προεπιλογή, το κλείσιμο θα εκτελεστεί επίσης με το σώμα λειτουργίας, εάν θέλετε να ξεφύγετε από το κλείσιμο της εκτέλεσης, το σημάδετε ως @escaping. Γιατί η Apple έκανε αυτή την αλλαγή; Ας το συζητήσουμε στο τέλος της συζήτησης .

1.Κλείδα κλεισίματος:

Όταν περνάει ένα κλείσιμο ως όρισμα λειτουργίας, το κλείσιμο γίνεται με το σώμα της λειτουργίας και επιστρέφει τον μεταγλωττιστή πίσω. Καθώς η εκτέλεση τελειώνει, το περατωμένο κλείσιμο εξέρχεται από το πεδίο εφαρμογής και δεν υπάρχει πλέον μνήμη.

Κύκλος ζωής του κλείστρου @nonescaping:
 1. Περάστε το κλείσιμο ως όρισμα λειτουργίας, κατά τη διάρκεια της κλήσης λειτουργίας.
 2. Κάντε κάποια επιπλέον εργασία με τη λειτουργία.
 3. Η λειτουργία εκτελεί το κλείσιμο.
 4. Η λειτουργία επιστρέφει τον μεταγλωττιστή πίσω.

Παράδειγμα:

func getSumOf (πίνακας: [Int], χειριστής: ((Int) -> άκυρο)) {
        //βήμα 2
        άθροισμα var: Int = 0
        για τιμή σε array {
            άθροισμα + = τιμή
        }}
        
        // βήμα 3
        χειριστής (άθροισμα)
    }}
    
    funk doSomething () {
        // setp 1
        self.getSumOf (πίνακας: [16,756,442,6,23]) {[αδύναμος εαυτός] (άθροισμα) σε
            εκτύπωση (άθροισμα)
            // βήμα 4, ολοκληρώνοντας την εκτέλεση
        }}
    }}
// Θα εκτυπώσει το σύνολο όλων των αριθμών.

Εδώ απλά ονομάσαμε τη λειτουργία με ένα κλείσιμο, που εκτελείται στο τέλος του σώματος της λειτουργίας.
Έτσι δεν ξεφεύγουμε από την εκτέλεση του κλεισίματος. Καθώς το βήμα 4 θα εκτελεστεί κλείσιμο δεν θα έχει καμία ύπαρξη στη μνήμη.

2. Αποφράξεις κλεισίματος:

Όταν περνάει ένα κλείσιμο ως όρισμα της λειτουργίας, το κλείσιμο διατηρείται για να εκτελεστεί αργότερα και το σώμα της λειτουργίας παίρνει εκτελεστεί, επιστρέφει τον μεταγλωττιστή πίσω. Καθώς τελειώνει η εκτέλεση, υπάρχει το πεδίο του περασμένου κλεισίματος και υπάρχει μνήμη, μέχρι να εκτελεστεί το κλείσιμο.
 Υπάρχουν διάφοροι τρόποι για να ξεφύγετε από το κλείσιμο:

  • Αποθήκευση: Όταν χρειάζεται να διατηρήσετε το αποθηκευτικό κλείσιμο που υπάρχει στη μνήμη, εκτελέστε το παρελθόν της λειτουργίας κλήσης και επιστρέψτε τον μεταγλωττιστή. (Όπως και σε αναμονή για την απάντηση API)
  • Ασύγχρονη εκτέλεση: Όταν εκτελέσετε το κλείδωμα ασύγχρονα στην ουρά αποστολής, η ουρά θα κρατήσει το κλείσιμο στη μνήμη για σας, το οποίο θα χρησιμοποιηθεί στο μέλλον. Σε αυτή την περίπτωση δεν έχετε ιδέα όταν το κλείσιμο θα εκτελεστεί.

Όταν θα προσπαθήσετε να χρησιμοποιήσετε το κλείσιμο με αυτές τις επιλογές, ο γρήγορος μεταγλωττιστής θα εμφανίσει το σφάλμα.

Κύκλος ζωής του κλείστρου @escaping:
1. Περάστε το κλείσιμο ως όρισμα λειτουργίας, κατά τη διάρκεια της κλήσης λειτουργίας.
2. Κάνετε κάποια επιπλέον εργασία σε λειτουργία.
3. Λειτουργία εκτελεί το κλείστρο ασύγχρονα ή αποθηκεύεται.
4. Η λειτουργία επιστρέφει τον μεταγλωττιστή πίσω.

Παράδειγμα 1 (Αποθήκευση):

var complitionHandler: ((Int) -> άκυρο);
    func getSumOf (πίνακας: [Int], χειριστής: @escaping ((Int) -> άκυρο)) {
        //βήμα 2
       // εδώ παίρνω για βρόχο ακριβώς για παράδειγμα, σε πραγματική περίπτωση θα είναι κάτι άλλο σαν κλήση API
       άθροισμα var: Int = 0
        για τιμή σε array {
            άθροισμα + = τιμή
        }}
// βήμα 3
        self.complitionHandler = χειριστής
    }}
    
    funk doSomething () {
        // setp 1
        self.getSumOf (πίνακας: [16,756,442,6,23]) {[αδύναμος εαυτός] (άθροισμα) σε
            εκτύπωση (άθροισμα)
            // βήμα 4, ολοκληρώνοντας την εκτέλεση
        }}
    }}
// Εδώ αποθηκεύουμε το κλείσιμο για μελλοντική χρήση.
// Θα εκτυπώσει το άθροισμα όλων των περασμένων αριθμών.

Παράδειγμα 2 (Ασύγχρονη Εκτέλεση):

func getSumOf (πίνακας: [Int], χειριστής: @escaping ((Int) -> άκυρο)) {
        //βήμα 2
        άθροισμα var: Int = 0
        για τιμή σε array {
            άθροισμα + = τιμή
        }}
        // βήμα 3
        Globals.delay (0,3, κλείσιμο: {
            χειριστής (άθροισμα)
        })
    }}
    
    funk doSomething () {
        // setp 1
        self.getSumOf (πίνακας: [16,756,442,6,23]) {[αδύναμος εαυτός] (άθροισμα) σε
            εκτύπωση (άθροισμα)
            // βήμα 4, ολοκληρώνοντας την εκτέλεση
        }}
    }}
// Εδώ καλούμε το κλείσιμο με καθυστέρηση 0,3 δευτερολέπτων
// Θα εκτυπώσει το άθροισμα όλων των περασμένων αριθμών.

Εδώ είμαστε με την έννοια του χαρακτηριστικού @escaping. Έτσι, όταν πρέπει να ξεφύγετε από την εκτέλεση του κλεισίματος, χρησιμοποιήστε το χαρακτηριστικό @escaping στο Swift 3. Το παραπάνω σφάλμα του μεταγλωττιστή θα εξαφανιστεί αφού κλείσετε ως διαφυγή χρησιμοποιώντας το χαρακτηριστικό @escaping.

Γιατί έκαναν @nonecaping από προεπιλογή;

Υπάρχουν πολλά διαφορετικά οφέλη από τη μη διαφυγή ως προεπιλογή. Τα σημαντικότερα οφέλη είναι η απόδοση και η βελτιστοποίηση κώδικα από τον μεταγλωττιστή, διότι αν ο μεταγλωττιστής γνωρίζει ότι το κλείσιμο δεν είναι διαφυγής, θα φροντίσει για την κατανομή μνήμης για το κλείσιμο.

Και ένα άλλο είναι ότι μπορούμε να χρησιμοποιήσουμε τον εαυτό μας χωρίς προβλήματα σε μη κλείδωμα που κλείνει επειδή το κλείσιμο εκτελείται πριν επιστρέψει η λειτουργία, ώστε ο εαυτός να είναι σίγουρος εκεί. Δεν χρειάζεται να χρησιμοποιήσουμε αδύναμους εαυτούς, αυτό είναι το πρόσθετο χαρακτηριστικό του.

Στο Swift 3, τα κλεισίματα δεν ξεφεύγουν από προεπιλογή, μπορούν να χρησιμοποιηθούν @escaping αν όχι αυτό που θέλουμε. Το μη κλειστό κλείδωμα θα εκτελείται προτού η λειτουργία επιστρέψει.
Να θυμάστε πάντα ότι χρησιμοποιείτε αδύναμο εαυτό ενώ χρησιμοποιείτε ένα κλείσιμο.

Σας ευχαριστούμε για την ανάγνωση, παρακαλώ πατήστε το εικονίδιο σύστασης εάν αυτή είναι αυτή η συλλογή. Ερωτήσεις; Αφήστε τα στο σχόλιο.