Class — είναι ένας τύπος αναφοράς (reference type) στη γλώσσα Swift, του οποίου τα στιγμιότυπα μεταδίδονται μέσω αναφοράς, όχι αντιγράφονται κατά την ανάθεση. Σε αντίθεση με τις δομές, οι κλάσεις υποστηρίζουν κληρονομικότητα, αποαρχικοποίηση και αυτόματη μέτρηση αναφορών ARC για διαχείριση μνήμης. Σύμφωνα με τον Swift Programming Language Guide, 2026, το class είναι απαραίτητο για εργασία με τα UI frameworks της Apple (UIKit, AppKit) και υλοποίηση προτύπων που απαιτούν κοινή ταυτότητα αντικειμένου. Η επιλογή μεταξύ class και struct είναι μία από τις βασικές αρχιτεκτονικές αποφάσεις στο Swift.
Κύρια σημεία
Class (κλάση) — είναι ένας σύνθετος τύπος αναφοράς στο Swift που ομαδοποιεί ιδιότητες και μεθόδους σε μια ενιαία οντότητα με υποστήριξη κληρονομικότητας και δυναμικής αποστολής. Σε αντίθεση με το struct, το στιγμιότυπο της κλάσης δημιουργείται στο heap, και η μεταβλητή αποθηκεύει μια αναφορά σε αυτό το στιγμιότυπο, όχι τα ίδια τα δεδομένα.
Όταν αναθέτετε μια μεταβλητή κλάσης σε άλλη μεταβλητή, και οι δύο αναφέρονται στο ίδιο αντικείμενο στη μνήμη. Οι αλλαγές μέσω μιας αναφοράς είναι ορατές μέσω της άλλης — αυτή είναι η θεμελιώδης ιδιότητα των reference types, που χρησιμοποιείται σε πρότυπα αντιπροσώπευσης, παρατήρησης και κοινής κατάστασης.
Σύμφωνα με την Apple Swift Documentation, οι κλάσεις είναι ο μόνος τρόπος εργασίας με UIKit και AppKit, όπου όλα τα UI components κληρονομούν από UIView και UIViewController. Επιπλέον, οι κλάσεις είναι απαραίτητες για την υλοποίηση προτύπων που απαιτούν ταυτότητα αντικειμένου (δύο αναφορές σε ένα αντικείμενο) και ελεγχόμενη διάρκεια ζωής.
Σημασιολογία reference type — η βασική ιδιότητα των κλάσεων. Κατά την ανάθεση μιας κλάσης σε μια νέα μεταβλητή, το Swift αντιγράφει την αναφορά, όχι τα δεδομένα. Όλες οι μεταβλητές που αναφέρονται στο ίδιο στιγμιότυπο βλέπουν την τρέχουσα κατάστασή του και μπορούν να την αλλάξουν. Αυτή η συμπεριφορά διαφέρει θεμελιωδώς από τα value types, όπου κάθε μεταβλητή λαμβάνει ένα ανεξάρτητο αντίγραφο.
// Παράδειγμα σημασιολογίας reference type
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — ίδια αναφορά
user2.name = "Bob"
print(user1.name) // "Bob" — άλλαξε μέσω user2!
// Έλεγχος ταυτότητας με τον τελεστή ===
print(user1 === user2) // true — ίδιο αντικείμενο
Οι τελεστές === (ταυτότητα) και !== ελέγχουν αν δύο μεταβλητές αναφέρονται στο ίδιο στιγμιότυπο κλάσης. Αυτή είναι η διαφορά από το == (ισότητα), που συγκρίνει τιμές ιδιοτήτων. Για το struct ο τελεστής === δεν είναι διαθέσιμος — τα value types δεν έχουν ταυτότητα.
Κληρονομικότητα — ο μηχανισμός με τον οποίο μια κλάση μπορεί να κληρονομήσει ιδιότητες και μεθόδους της γονικής κλάσης. Στο Swift μια κλάση μπορεί να κληρονομήσει μόνο από έναν γονέα (single inheritance), αλλά μπορεί να υλοποιήσει πολλαπλά πρωτόκολλα. Η λέξη-κλειδί override επιτρέπει την παράκαμψη μιας κληρονομημένης μεθόδου ή ιδιότητας.
Κάθε κλάση που δεν κληρονομεί από άλλη κλάση γίνεται αυτόματα βασική (μην συγχέεται με το NSObject). Η υποκλάση υποδεικνύει τον γονέα με άνω τελεία μετά το όνομα. Εάν η υποκλάση παρακάμπτει τη μέθοδο του γονέα, πρέπει να καλέσει super.μέθοδο() για να διατηρήσει τη συμπεριφορά του γονέα — αυτό είναι απαίτηση του μεταγλωττιστή.
Η λέξη-κλειδί final πριν από το class απαγορεύει την κληρονομικότητα. Ο μεταγλωττιστής μπορεί να βελτιστοποιήσει τις κλήσεις μεθόδων των final κλάσεων μέσω static dispatch, βελτιώνοντας την απόδοση. Χρησιμοποιήστε final για κλάσεις που δεν προορίζονται για επέκταση — αυτό τεκμηριώνει την πρόθεσή σας και επιταχύνει τον κώδικα.
// Παράδειγμα κληρονομικότητας κλάσεων στο Swift
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car κληρονομεί από Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// Final class — αποτρέπει κληρονομικότητα
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
Η κληρονομικότητα κλάσεων είναι ένας ισχυρός αλλά υπεύθυνος μηχανισμός. Η βαθιά ιεραρχία (5+ επίπεδα) δυσκολεύει τη συντήρηση και τη δοκιμή. Για επαναχρησιμοποίηση λειτουργικότητας χωρίς κληρονομικότητα χρησιμοποιήστε πρωτόκολλα με extension και προγραμματισμό προσανατολισμένο σε πρωτόκολλα — μια προσέγγιση που η Apple προωθεί ως εναλλακτική για βαθιές ιεραρχίες κλάσεων.
Το Swift χρησιμοποιεί ARC (Automatic Reference Counting) για τη διαχείριση μνήμης των κλάσεων. Κάθε στιγμιότυπο κλάσης έχει έναν μετρητή ισχυρών αναφορών. Κατά τη δημιουργία μιας νέας ισχυρής αναφοράς ο μετρητής αυξάνεται· κατά την καταστροφή — μειώνεται. Όταν ο μετρητής φτάσει στο μηδέν, η μνήμη ελευθερώνεται.
Deinit — μέθοδος που καλείται αυτόματα πριν από την απελευθέρωση του στιγμιοτύπου της κλάσης. Σε αυτήν ελευθερώνονται πόροι: κλείνουν αρχεία, γίνεται απεγγραφή από ειδοποιήσεις, σταματούν χρονοδιακόπτες. Το deinit υπάρχει μόνο στις κλάσεις — οι δομές και οι απαριθμήσεις δεν το έχουν.
Για την πρόληψη κύκλων ισχυρών αναφορών (retain cycles), το Swift παρέχει weak και unowned αναφορές. Weak — μια προαιρετική αναφορά που γίνεται αυτόματα nil κατά την απελευθέρωση του αντικειμένου. Unowned — μη προαιρετική, αλλά αναφέρεται σε ένα αντικείμενο που εγγυημένα ζει περισσότερο από το τρέχον πλαίσιο. Ένας τυπικός retain cycle προκύπτει στη σχέση parent-child: το child διατηρεί μια ισχυρή αναφορά στο parent.
// Παράδειγμα ARC και αδύναμης αναφοράς
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) αποδεσμεύτηκε") }
}
class Child {
var name: String
weak var parent: Parent? // weak αποτρέπει retain cycle
init(name: String) { self.name = name }
deinit { print("\(name) αποδεσμεύτηκε") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // Και τα δύο αντικείμενα αποδεσμεύτηκαν!
// Χωρίς weak θα δημιουργούσε retain cycle
Χρησιμοποιείτε πάντα weak για αναφορές από το θυγατρικό αντικείμενο προς το γονικό και για λίστες capture σε closures. Χρησιμοποιήστε unowned μόνο όταν είστε σίγουροι ότι το αντικείμενο θα επιζήσει του τρέχοντος πλαισίου — η λανθασμένη χρήση unowned μπορεί να οδηγήσει σε crash κατά την πρόσβαση σε απελευθερωμένη μνήμη.
Η επιλογή μεταξύ class και struct είναι μια αρχιτεκτονική απόφαση που επηρεάζει την απόδοση, την ασφάλεια νημάτων και τον σχεδιασμό API. Ας εξετάσουμε τον πίνακα βασικών διαφορών που θα βοηθήσει στη λήψη της σωστής απόφασης σε κάθε συγκεκριμένη περίπτωση.
| Χαρακτηριστικό | class | struct |
|---|---|---|
| Τύπος | Reference type (αναφορά) | Value type (αντίγραφο) |
| Μνήμη | Heap + ARC | Stack / inline |
| Κληρονομικότητα | Υποστηρίζει (ένας γονέας) | Δεν υποστηρίζει |
| Deinit | Υπάρχει | Δεν υπάρχει |
| Ταυτότητα (===) | Υποστηρίζει | Δεν υποστηρίζει |
| Mutating | Δεν απαιτείται (πάντα mutating) | Μόνο με mutating |
| Memberwise init | Δεν παράγεται | Παράγεται αυτόματα |
| Ασφάλεια νημάτων | Δεν είναι εγγυημένη (κοινή κατάσταση) | Εγγυημένη (αντιγραφή) |
Χρησιμοποιήστε κλάσεις όταν χρειάζεστε κοινή ταυτότητα (πολλά μέρη κώδικα εργάζονται με ένα αντικείμενο), κληρονομικότητα ή αλληλεπίδραση με Objective-C runtime. Για όλα τα άλλα, προτιμώνται οι δομές — είναι ταχύτερες, ασφαλέστερες σε πολυνηματικό κώδικα και δεν απαιτούν διαχείριση μνήμης.
Παρά τη σύσταση της Apple να χρησιμοποιείτε struct από προεπιλογή, οι κλάσεις είναι απαραίτητες σε μερικά συγκεκριμένα σενάρια. Ας εξετάσουμε το καθένα με πρακτικά παραδείγματα.
Όλα τα UI components σε iOS και macOS είναι κλάσεις που κληρονομούν από UIView (iOS) ή NSView (macOS). Δεν μπορείτε να αντικαταστήσετε το UIViewController με μια δομή — απαιτεί κληρονομικότητα και deinit για την απελευθέρωση πόρων. Κατά την εργασία με UIKit χρησιμοποιήστε κλάσεις για controllers, views και τους delegates τους.
Το πρότυπο Singleton (ένα στιγμιότυπο κλάσης για ολόκληρη την εφαρμογή) απαιτεί σημασιολογία αναφοράς. Διαχειριστές: NetworkManager, SettingsManager, AnalyticsService — συνήθως υλοποιούνται ως κλάσεις με shared static property. Οι δομές δεν είναι κατάλληλες γιατί κάθε αντίγραφο θα ήταν ανεξάρτητο στιγμιότυπο.
Όταν ένα αντικείμενο πρέπει να είναι μοναδική πηγή αλήθειας (single source of truth) και μεταδίδεται μεταξύ μονάδων μέσω αναφοράς — χρησιμοποιήστε class. Αυτό αφορά τη διαχείριση κατάστασης όπου η αλλαγή του αντικειμένου σε ένα μέρος πρέπει να είναι ορατή σε όλα τα εξαρτώμενα components. Για ObservableObject στο SwiftUI οι κλάσεις είναι υποχρεωτικές.
// ObservableObject — class απαραίτητο για SwiftUI
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// Χρήση σε SwiftUI View
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "Καλώς ήρθατε" : "Σύνδεση")
}
}
Κανόνας: αν ένα αντικείμενο πρέπει να έχει ταυτότητα (δύο αναφορές -> ένα αντικείμενο), να είναι μοναδικό στιγμιότυπο ή να λειτουργεί με UIKit/Objective-C — επιλέξτε class. Αν το αντικείμενο απλώς αποθηκεύει δεδομένα — επιλέξτε struct.
Συχνές ερωτήσεις
Class — είναι ένας τύπος αναφοράς (reference type) στο Swift που υποστηρίζει κληρονομικότητα, αποαρχικοποίηση και ARC για διαχείριση μνήμης. Τα στιγμιότυπα κλάσεων αποθηκεύονται στο heap και οι μεταβλητές περιέχουν μια αναφορά στο αντικείμενο, όχι το αντίγραφό του.
Class — reference type (μεταδίδεται μέσω αναφοράς), υποστηρίζει κληρονομικότητα και deinit. Struct — value type (αντιγράφεται), δεν υποστηρίζει κληρονομικότητα, αλλά υλοποιεί πρωτόκολλα και λαμβάνει αυτόματα memberwise init. Η Swift συνιστά το struct ως προεπιλεγμένο τύπο.
ARC (Automatic Reference Counting) — μηχανισμός διαχείρισης μνήμης για τις κλάσεις Swift. Κάθε στιγμιότυπο έχει έναν μετρητή ισχυρών αναφορών. Όταν ο μετρητής φτάσει στο μηδέν, η μνήμη ελευθερώνεται. Οι weak και unowned αναφορές αποτρέπουν τους retain cycles μεταξύ αντικειμένων.
Deinit — μέθοδος της κλάσης που καλείται αυτόματα πριν από την απελευθέρωση της μνήμης της. Χρησιμοποιείται για κλείσιμο αρχείων, απεγγραφή από ειδοποιήσεις και άλλες τελικές λειτουργίες. Το deinit υπάρχει μόνο στις κλάσεις — οι δομές δεν το έχουν.
Χρησιμοποιήστε class για UI components UIKit/AppKit, singleton, ObservableObject στο SwiftUI, αντικείμενα με κοινή ταυτότητα (delegate, observer) και κατά την εργασία με Objective-C runtime. Για μοντέλα δεδομένων, DTO και διαμορφώσεις προτιμάται το struct.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης