Closures στο Swift: Ισχυρές και Ευέλικτες Συναρτήσεις

Ξείνηε από Vuyok, Δεκ 26, 2025, 10:26 Π

« προηγούενο - εόμενο »

Vuyok

Στο Swift, τα closures ορίζονται ως ανώνυμες (χωρίς όνομα) συναρτήσεις και μπορείτε να τα εκχωρήσετε σε μια μεταβλητή, να τα περάσετε ως παραμέτρους ή να τα χρησιμοποιήσετε ως τιμή επιστροφής. Τα closures είναι ένα από τα πιο ισχυρά χαρακτηριστικά του Swift και χρησιμοποιούνται συχνά σε μεθόδους όπως map, filter, sorted του Array, σε completion handlers και σε ασύγχρονες λειτουργίες. Σε αυτό το άρθρο, θα εξετάσουμε τη βασική χρήση των closures, τη σύνταξή τους, τα trailing closures και τη συμπεριφορά capturing με λεπτομερή παραδείγματα.

Βασική Σύνταξη Closure

Ένα closure έχει την εξής δομή:

Απλό Παράδειγμα:
Χωρίς παραμέτρους και τύπο επιστροφής:
Πέρασμα Closure ως Παραμέτρου σε Συναρτήσεις
Τα closures χρησιμοποιούνται συχνότερα ως completion handlers.
Κώδικας [Επιλογή]
func islemYap(sayi1: Int, sayi2: Int, operasyon: (Int, Int) -> Int) -> Int {
    return operasyon(sayi1, sayi2)
}
// Χρήση
let toplam = islemYap(sayi1: 5, sayi2: 3) { (a, b) in return a + b }
print(toplam) // 8
// Πιο σύντομο
let carpim = islemYap(sayi1: 4, sayi2: 5) { $0 * $1 }
print(carpim) // 20


Με shorthand syntax όπως $0, $1 μπορείτε να χρησιμοποιήσετε χωρίς να γράφετε ονόματα παραμέτρων.

Σύνταξη Trailing Closure
Αν η τελευταία παράμετρος μιας συνάρτησης είναι closure, μπορεί να γραφτεί έξω από τις παρενθέσεις.
Κώδικας [Επιλογή]
// Κανονική χρήση
UIView.animate(withDuration: 1.0, animations: { view.alpha = 0 })
// Trailing closure (πιο καθαρό)
UIView.animate(withDuration: 1.0) { view.alpha = 0 }

Χρήση Closure σε Συνήθεις Μεθόδους Array
Κώδικας [Επιλογή]
let sayilar = [3, 1, 4, 1, 5, 9, 2]

// map: Μετατροπή κάθε στοιχείου
let kareler = sayilar.map { $0 * $0 }
print(kareler) // [9, 1, 16, 1, 25, 81, 4]

// filter: Επιλογή αυτών που ταιριάζουν στην συνθήκη
let ciftler = sayilar.filter { $0 % 2 == 0 }
print(ciftler) // [4, 2]

// sorted: Ταξινόμηση
let sirali = sayilar.sorted { $0 < $1 }
print(sirali) // [1, 1, 2, 3, 4, 5, 9]

Capturing Values (Σύλληψη Τιμών)
Τα closures μπορούν να "συλλάβουν" (capture) τις μεταβλητές από το περιβάλλον τους. Αυτό είναι ένα χαρακτηριστικό που χρειάζεται προσοχή, ειδικά σε ασύγχρονες λειτουργίες.
Κώδικας [Επιλογή]
func asenkronIslem(completion: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        completion()
    }
}
var mesaj = "Başlangıç"
let closure = {
    print(mesaj) // Το closure συλλαμβάνει τη μεταβλητή mesaj
}
mesaj = "Değiştirildi"
closure() // Έξοδος: Değiştirildi


Διαχείριση weak/self με Capturing List (πρόληψη memory leak):
Κώδικας [Επιλογή]
class Ornek {
    var deger = 0
    lazy var closure: () -> Void = { [weak self] in
        guard let self = self else { return }
        print(self.deger)
    }
}

Τα @escaping closures πρέπει να δηλώνονται αν εκτελούνται μετά την έξοδο από τη συνάρτηση.
Σύγκριση: Closure vs Κανονική Συνάρτηση
  • Χαρακτηριστικό: Όνομα Κανονική Συνάρτηση: Υπάρχει Closure: Συνήθως όχι (ανώνυμο)
  • Χαρακτηριστικό: Ορισμός Κανονική Συνάρτηση: Με def Closure: Με {} μπλοκ
  • Χαρακτηριστικό: Πέρασμα ως παραμέτρου Κανονική Συνάρτηση: Ναι Closure: Πολύ εύκολο και συχνά χρησιμοποιούμενο
  • Χαρακτηριστικό: Trailing syntax Κανονική Συνάρτηση: Όχι Closure: Ναι (πιο αναγνώσιμο)
  • Χαρακτηριστικό: Capturing Κανονική Συνάρτηση: Όχι Closure: Ναι (συλλαμβάνει τιμές από το περιβάλλον)
  • Χαρακτηριστικό: Πεδίο Χρήσης Κανονική Συνάρτηση: Γενικού σκοπού Closure: Completion handler, map/filter κλπ.

Καλύτερες Πρακτικές
• Σε σύντομα closures χρησιμοποιήστε shorthand $0, $1.
• Σε ασύγχρονα closures δηλώστε @escaping.
• Για πρόληψη memory leak χρησιμοποιήστε [weak self] ή [unowned self].
• Για αναγνωσιμότητα, βγάλτε πολύ μεγάλα closures σε ξεχωριστές συναρτήσεις.

Συμπέρασμα
Τα closures στο Swift κάνουν τον κώδικα σας πιο ευέλικτο και σύντομο. Ειδικά σε υψηλού επιπέδου μεθόδους (map, filter, reduce) και ασύγχρονο προγραμματισμό είναι απαραίτητα. Ξεκινήστε με απλά παραδείγματα για να εξοικειωθείτε, με τον καιρό θα τα χρησιμοποιείτε άνετα σε completion handlers και animations.
Για πρακτική, γράψτε μια εφαρμογή επεξεργασίας δεδομένων σε ένα array χρησιμοποιώντας συνδυασμό map, filter και reduce!
Περιμένω τις ερωτήσεις σας στα σχόλια.