Middle
Εξηγήστε τη διαφορά μεταξύ closures escaping και non-escaping, και σε ποιες περιπτώσεις είναι απαραίτητο να χρησιμοποιήσετε το @escaping.
sobes.tech AI
Απάντηση από AI
Οι προεπιλεγμένες κλεισίματα είναι μη-escape.
Μη-escape κλείσιμο:
- Εκτελείται στο σώμα της λειτουργίας στην οποία περνάει.
- Συλλαμβάνει μεταβλητές, αλλά τις απελευθερώνει μετά την ολοκλήρωση της λειτουργίας.
- Δεν επιβιώνει της λειτουργίας.
func doSomething(completion: () -> Void) {
// Κλήση completion εδώ
completion()
}
Escape κλείσιμο:
- Εκτελείται μετά την επιστροφή της λειτουργίας στην οποία περνάει.
- Επιβιώνει του σώματος της λειτουργίας.
- Μπορεί να αποθηκευτεί για μελλοντική εκτέλεση, π.χ., σε άλλο νήμα ή ασύγχρονα.
- Συλλαμβάνει μεταβλητές, διατηρώντας ισχυρές αναφορές, που μπορεί να οδηγήσει σε κύκλους ισχυρών αναφορών (retain cycles). Απαιτεί ρητή δήλωση
@escaping.
class DataManager {
var completionHandlers: [() -> Void] = []
func addCompletionHandler(handler: @escaping () -> Void) {
completionHandlers.append(handler)
}
func performTasks() {
// Εκτέλεση εργασιών...
for handler in completionHandlers {
handler() // Κλήση handlers αργότερα
}
}
}
Η χρήση του @escaping είναι απαραίτητη στις ακόλουθες περιπτώσεις:
- Όταν η κλείσιμο αποθηκεύεται σε ιδιότητα μιας κλάσης ή δομής.
- Όταν η κλείσιμο περνά σε άλλο νήμα ή ασύγχρονη λειτουργία (π.χ., αίτημα δικτύου, GCD, OperationQueue).
- Όταν η κλείσιμο χρησιμοποιείται ως χειριστής συμβάντος ή delegate.