Middle
Μίλησε για τη λίστα capture στο Swift.
sobes.tech AI
Απάντηση από AI
Η λίστα σύλληψης (capture list) στη Swift χρησιμοποιείται για τον έλεγχο της άμεσης σύλληψης μεταβλητών από κλεισίματα (closures). Αυτό βοηθά στην αποφυγή ισχυρών κύκλων αναφορών, ειδικά κατά την εργασία με το self μέσα σε κλεισίματα που χρησιμοποιούνται σε κλάσεις. Οι κύριοι τύποι σύλληψης είναι: weak και unowned.
| Τύπος σύλληψης | Περιγραφή | Πότε να χρησιμοποιήσετε |
|---|---|---|
weak |
Συλλαμβάνει τη μεταβλητή ως προαιρετική, χωρίς να αυξάνει τον μετρητή αναφορών. Η τιμή της μπορεί να γίνει nil. |
Όταν το αντικείμενο του κλεισίματος μπορεί να επιβιώσει από το συλληφθέν αντικείμενο. |
unowned |
Συλλαμβάνει τη μεταβλητή χωρίς να αυξάνει τον μετρητή αναφορών, αλλά θεωρείται ότι το συλληφθέν αντικείμενο θα ζει όσο το κλείσιμο. Δεν είναι προαιρετικό. | Όταν το αντικείμενο του κλεισίματος και το συλληφθέν αντικείμενο έχουν την ίδια διάρκεια ζωής, και το συλληφθέν αντικείμενο δεν θα γίνει nil πριν το κλείσιμο ολοκληρωθεί. |
Σύνταξη λίστας σύλληψης:
{ [capture list] (παραμέτρους) -> τύπος επιστροφής in
// κώδικας
}
Παράδειγμα χρήσης weak self:
class MyClass {
var value = 0
func doSomethingLater() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return } // έλεγχος για `nil`
self.value += 1
print("Τιμή τώρα είναι \(self.value)")
}
}
}
Παράδειγμα χρήσης unowned self:
class ViewController: UIViewController {
var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton(type: .system)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
@objc func buttonTapped() {
// unowned self δεν απαιτείται σε αυτήν την περίπτωση, καθώς το κουμπί υπάρχει όσο και το ViewController.
// Αλλά αν το κλείσιμο μπορεί να επιβιώσει από το ViewController, το unowned θα ήταν κατάλληλο αν
// είστε βέβαιοι ότι το self δεν θα γίνει `nil`.
let action = { [unowned self] in
self.view.backgroundColor = .blue
}
action()
}
}
Μπορείτε να συλλάβετε όχι μόνο το self, αλλά και οποιεσδήποτε άλλες μεταβλητές που είναι διαθέσιμες στο κλείσιμο. Για παράδειγμα, για να αποθηκεύσετε την τιμή μιας μεταβλητής τη στιγμή της δημιουργίας του κλεισίματος:
func createIncrementer(initialValue: Int) -> () -> Int {
var currentValue = initialValue
return { [initialValue] in // Συλλαμβάνει το initialValue ως τιμή
currentValue += 1
print("Αρχική τιμή ήταν \(initialValue)") // το initialValue διατηρεί την τιμή του
return currentValue
}
}
let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Έξοδος: Αρχική τιμή ήταν 5, μετά 6
print(incrementer()) // Έξοδος: Αρχική τιμή ήταν 5, μετά 7