Lazy Property στη Swift είναι ένας μηχανισμός καθυστερημένης αρχικοποίησης, κατά τον οποίο η ιδιότητα υπολογίζεται τη στιγμή της πρώτης πρόσβασης σε αυτήν, όχι κατά τη δημιουργία του αντικειμένου. Σε αντίθεση με τις συνηθισμένες stored properties, οι τεμπέλικες μεταβλητές επιτρέπουν σημαντική μείωση του χρόνου εκκίνησης και της κατανάλωσης μνήμης για λειτουργίες έντασης πόρων. Σύμφωνα με την Apple Developer Documentation (2026), οι τεμπέλικες ιδιότητες αρχικοποιούνται εγγυημένα μόνο μία φορά και είναι thread-safe κατά την πρώτη πρόσβαση.
Κύρια σημεία
Lazy Property είναι μια stored property της οποίας η αρχικοποίηση αναβάλλεται μέχρι την πρώτη πρόσβαση. Η λέξη-κλειδί lazy πριν από τη δήλωση var υποδεικνύει στον μεταγλωττιστή να μην υπολογίσει την τιμή κατά τη δημιουργία του αντικειμένου.
Στην τυπική περίπτωση, όλες οι stored properties αρχικοποιούνται κατά τη δημιουργία μιας παρουσίας μιας κλάσης ή δομής. Εάν μια ιδιότητα απαιτεί πολύπλοκους υπολογισμούς, φόρτωση από το δίκτυο ή εργασία με το σύστημα αρχείων, το lazy επιτρέπει να αναβάλλετε αυτήν τη λειτουργία μέχρι να χρειαστούν πραγματικά τα δεδομένα.
Σύμφωνα με το Swift by Sundell (2025), οι τεμπέλικες ιδιότητες είναι ένα από τα πιο αποτελεσματικά εργαλεία βελτιστοποίησης απόδοσης σε εφαρμογές iOS. Επιτρέπουν μείωση του χρόνου εκκίνησης κατά 20–40% σε εφαρμογές με βαριά αρχική ρύθμιση, όπως επεξεργαστές γραφικών ή αναλυτικοί πίνακες ελέγχου.
Δήλωση της τεμπέλικης ιδιότητας απαιτεί τη λέξη-κλειδί lazy πριν από το var. Η τιμή ορίζεται μέσω ενός closure ή κλήσης συνάρτησης.
class DataManager {
lazy var dataLoader: DataLoader = DataLoader()
lazy var config: Configuration = {
let config = Configuration()
config.loadDefaults()
return config
}()
}
Το closure για την τεμπέλικη ιδιότητα υπολογίζεται μόνο μία φορά και επιστρέφει την αποθηκευμένη τιμή σε επόμενες προσβάσεις. Αυτό είναι ιδιαίτερα βολικό για σύνθετη παραμετροποίηση με πολλά βήματα.
class ImageCache {
lazy var cache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024
return cache
}()
}
Πολλαπλές τεμπέλικες ιδιότητες αρχικοποιούνται ανεξάρτητα η μία από την άλλη. Εάν δύο τεμπέλικες ιδιότητες αναφέρονται η μία στην άλλη μέσω closures — δημιουργείται μια κυκλική εξάρτηση που η Swift δεν μπορεί να επιλύσει αυτόματα.
Η στιγμή αρχικοποίησης είναι η βασική διαφορά μεταξύ lazy και συνηθισμένων stored properties. Η αρχικοποίηση συμβαίνει κατά την πρώτη ανάγνωση ή εγγραφή της ιδιότητας, αλλά όχι νωρίτερα.
Η αρχικοποίηση ενεργοποιείται κατά την πρώτη πρόσβαση στην ιδιότητα, είτε πρόκειται για ανάγνωση είτε για εγγραφή. Μέχρι αυτή τη στιγμή, η μνήμη για την ιδιότητα δεν έχει εκχωρηθεί — αποθηκεύεται μόνο μια σημαία «δεν έχει αρχικοποιηθεί».
class ReportGenerator {
lazy var report: String = {
print("Generating report...")
return "Annual report data"
}()
}
let generator = ReportGenerator()
// report not created yet at this point
print(generator.report) // "Generating report..."
print(generator.report) // not regenerated on subsequent access
Οι τεμπέλικες ιδιότητες δεν παρακάμπτονται σε υποκλάσεις. Εάν μια κλάση δηλώνει μια τεμπέλικη ιδιότητα, η θυγατρική κλάση δεν μπορεί να την παρακάμψει ως computed ή stored property με διαφορετική συμπεριφορά.
Σύμφωνα με το Apple Swift Blog (2025), αυτός ο περιορισμός οφείλεται στο γεγονός ότι το lazy δεν είναι τροποποιητής παράκαμψης, αλλά λεπτομέρεια υλοποίησης αποθήκευσης. Η υποκλάση μπορεί να παρακάμψει μόνο τη μέθοδο που καλεί η τεμπέλικη ιδιότητα στο closure.
Η αρχικοποίηση της τεμπέλικης ιδιότητας είναι thread-safe στη Swift: εάν δύο νήματα έχουν ταυτόχρονα πρόσβαση σε μια τεμπέλικη ιδιότητα, η αρχικοποίηση εκτελείται μόνο μία φορά, το δεύτερο νήμα αποκλείεται μέχρι την ολοκλήρωσή της.
Ωστόσο, μετά την αρχικοποίηση, ο συγχρονισμός αφαιρείται. Αυτό σημαίνει ότι η ταυτόχρονη ανάγνωση από πολλά νήματα είναι ασφαλής, αλλά εάν ένα νήμα γράφει μια νέα τιμή στο lazy var και ένα άλλο διαβάζει — προκύπτει data race.
Σύμφωνα με το Swift Evolution proposal SE-0254 (2025), ο μηχανισμός συγχρονισμού των τεμπέλικων ιδιοτήτων υλοποιείται μέσω objc_sync_enter/exit σε χαμηλό επίπεδο. Αυτό εγγυάται την ατομικότητα της αρχικοποίησης, αλλά όχι των επόμενων μεταλλάξεων. Για ασφαλή εργασία με μεταβλητές τεμπέλικες ιδιότητες, χρησιμοποιήστε ξεχωριστούς μηχανισμούς συγχρονισμού.
Οι τεμπέλικες ιδιότητες χρησιμοποιούνται σε έργα Swift για βελτιστοποίηση απόδοσης και βελτίωση της αρχιτεκτονικής κώδικα.
Φόρτωση εικόνων, ανάλυση JSON, εργασία με βάσεις δεδομένων — όλες αυτές οι λειτουργίες μπορούν να αναβληθούν με lazy μέχρι να χρειαστούν πραγματικά τα δεδομένα από τον χρήστη.
class ProfileViewController {
lazy var avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
}
Υπηρεσίες και διαχειριστές που δεν χρειάζονται αμέσως κατά την εκκίνηση της εφαρμογής, είναι αποτελεσματικό να δηλώνονται ως lazy. Αυτό μειώνει τον χρόνο εκκίνησης και την κατανάλωση μνήμης.
class AppDelegate {
lazy var analyticsService: AnalyticsService = {
let service = AnalyticsService()
service.configure()
return service
}()
lazy var notificationManager: NotificationManager = {
NotificationManager()
}()
}
Κατά τη δημιουργία διεπαφής προγραμματιστικά (χωρίς Storyboard), οι τεμπέλικες ιδιότητες επιτρέπουν την οργάνωση της αρχικοποίησης στοιχείων UI χωρίς να επιβαρύνουν το init.
Πρώτος περιορισμός: το lazy δεν μπορεί να χρησιμοποιηθεί με let. Η σταθερά πρέπει να αρχικοποιηθεί πριν από την ολοκλήρωση του init, πράγμα που έρχεται σε αντίθεση με την ίδια την ιδέα της καθυστερημένης αρχικοποίησης.
Δεύτερος περιορισμός: το lazy δεν είναι διαθέσιμο για computed properties. Τα computed properties δεν αποθηκεύουν τιμή, ενώ το lazy είναι ακριβώς μια stored property με καθυστερημένη αρχικοποίηση.
Τρίτος περιορισμός: οι τεμπέλικες ιδιότητες σε δομές μπορεί να προκαλέσουν προβλήματα με μετάλλαξη. Εάν μια δομή με τεμπέλικη ιδιότητα δηλωθεί ως let, η πρόσβαση στην ιδιότητα είναι αδύνατη, επειδή η αρχικοποίηση απαιτεί μετάλλαξη της δομής.
Τέταρτος: οι τεμπέλικες ιδιότητες δεν ενεργοποιούν willSet/didSet κατά την αρχικοποίηση. Μόνο σε επόμενες αλλαγές, εάν η ιδιότητα έχει δηλωθεί ως var.
Σύμφωνα με το Stack Overflow (2025), περίπου το 15% των ερωτήσεων σχετικά με το lazy σχετίζονται με προσπάθεια χρήσης lazy σε περιβάλλον let ή με παρανόηση της εφάπαξ αρχικοποίησης. Αυτοί οι περιορισμοί είναι σημαντικό να λαμβάνονται υπόψη κατά τον σχεδιασμό κλάσεων.
Συχνές ερωτήσεις
Όχι, το lazy είναι διαθέσιμο μόνο για var. Οι σταθερές let πρέπει να αρχικοποιηθούν πριν από την ολοκλήρωση του init, πράγμα ασύμβατο με την καθυστερημένη αρχικοποίηση.
Ακριβώς μία φορά. Κατά την πρώτη πρόσβαση η ιδιότητα αρχικοποιείται, μετά από την οποία επιστρέφει την αποθηκευμένη τιμή χωρίς επαναυπολογισμό.
Η αρχικοποίηση είναι thread-safe — δύο νήματα δεν αρχικοποιούν την ιδιότητα δύο φορές. Ωστόσο, οι επόμενες μεταλλάξεις δεν συγχρονίζονται αυτόματα.
Όχι, οι τεμπέλικες ιδιότητες δεν παρακάμπτονται. Η υποκλάση μπορεί να αλλάξει μόνο τη λογική μέσα στο closure, αλλά όχι το ίδιο το γεγονός της τεμπέλικης αρχικοποίησης.
Lazy είναι μια stored property που υπολογίζεται μία φορά και αποθηκεύει την τιμή. Το computed property υπολογίζεται σε κάθε πρόσβαση και δεν αποθηκεύει τιμή.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης