ARC: τι είναι, αρχή λειτουργίας Automatic Reference Counting στο iOS

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-29 Χρόνος ανάγνωσης: 8 λεπ

Automatic Reference Counting (ARC) — σύστημα διαχείρισης μνήμης στο Swift και Objective-C που μετράει αυτόματα τον αριθμό αναφορών προς κάθε αντικείμενο και το απελευθερώνει όταν ο αριθμητής φτάσει στο μηδέν. Σύμφωνα με τα Apple Swift Documentation, 2026, το ARC ενσωματώνεται στον μεταγλωττιστή και λειτουργεί στη φάση μεταγλώττισης, εισάγοντας κλήσεις retain/release στα κατάλληλα σημεία. Σε αντίθεση με το Garbage Collection, το ARC δεν απαιτεί ξεχωριστό νήμα συλλογής και δημιουργεί παύσεις κατά τη διάρκεια εκτέλεσης της εφαρμογής.

Βασικά σημεία

  • ARC — Automatic Reference Counting, σύστημα διαχείρισης μνήμης μεταγλωττιστή σε Swift και Objective-C
  • Αρχή λειτουργίας — κάθε αντικείμενο έχει αριθμητή αναφορών (retain count), στο μηδενισμό το αντικείμενο απελευθερώνεται αμέσως
  • Προσδιοριστές — strong, weak και unowned καθορίζουν πώς η αναφορά επηρεάζει τον αριθμητή και τον κύκλο ζωής του αντικειμένου
  • Διαφορά από GC — το ARC λειτουργεί ντετερμινιστικά στη φάση μεταγλώττισης, χωρίς παύσεις Stop-The-World και νήμα φόντου συλλογής
  • Retain Cycle — το κύριο πρόβλημα του ARC: αν δύο αντικείμενα αναφέρονται το ένα στο άλλο μέσω strong, ο αριθμητής τους ποτέ δεν μηδενίζεται

Τι είναι το ARC;

ARC (Automatic Reference Counting) — είναι ένας μηχανισμός διαχείρισης μνήμης σε επίπεδο μεταγλωττιστή, που εισήχθηκε από την Apple στο Xcode 4.2 (2011) για το Objective-C και κληρονομήθηκε από το Swift. Σε αντίθεση με τη χειροκινητική διαχείριση μνήμης (Manual Retain-Release, MRR), το ARC αυτοματοποιεί πλήρως τις κλήσεις retain, release και autorelease, εισάγοντάς τις στη φάση μεταγλώττισης χωρίς τη συμμετοχή του προγραμματιστή.

Το ARC δεν είναι garbage collector. Είναι μια στατική ανάλυση με δυναμική εισαγωγή κώδικα: ο μεταγλωττιστής αναλύει τη διάρκεια ζωής των αντικειμένων και τοποθετεί τα retain/release σε σημεία όπου τα αντικείμενα δημιουργούνται, αντιγράφονται ή εγκαταλείπουν το πεδίο ορατότητας. Το αποτέλεσμα — ντετερμινιστική απελευθέρωση μνήμης: το αντικείμενο διαγράφεται ακριβώς τη στιγμή που παύουν να υπάρχουν αναφορές σε αυτό, χωρίς καθυστερήσεις και παύσεις.

Σύμφωνα με το WWDC 2011 Session 323, η μετάβαση από MRR σε ARC μείωσε τον αριθμό των crash-bug που σχετίζονται με τη μνήμη κατά 70% σε εφαρμογές Apple. Οι προγραμματιστές σταμάτησαν να εξισορροπούν χειροκινητικά τα retain/release, καταργώντας μια ολόκληρη κλάση διαρροών και σφαλμάτων double-free.

Πώς λειτουργεί το Automatic Reference Counting

Κάθε αντικείμενο στη μνήμη έχει έναν αριθμητή αναφορών (retain count). Κατά τη δημιουργία του αντικειμένου, ο αριθμητής ορίζεται σε 1. Όταν μια νέα strong-αναφορά δείχνει στο αντικείμενο — ο αριθμητής αυξάνει (retain). Όταν η strong-αναφορά εξαφανίζεται — ο αριθμητής μειώνεται (release). Μόλις φτάσει στο μηδέν, το αντικείμενο απελευθερώνεται αμέσως.

Ο μεταγλωττιστής Swift δεν εισάγει retain/release σε κάθε ανάθεση — χρησιμοποιεί στατική ανάλυση για βελτιστοποίηση. Για παράδειγμα, εάν ένα αντικείμενο είναι εγγυημένο ότι δεν θα χρησιμοποιηθεί μετά τη μεταφορά, ο μεταγλωττιστής μπορεί να παραλείψει τον περιττό release/retain. Αυτή η βελτιστοποίηση ονομάζεται ARC Optimisation.

swift
class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) αρχικοποιήθηκε (retain count: 1)")
    }
    deinit {
        print("\(name) απελευθερώθηκε")
    }
}

func testARC() {
    let p = Person(name: "Alice")  // retain count = 1
    let q = p                      // retain count = 2
    // q εγκαταλείπει το πεδίο
    // retain count = 1
    // p εγκαταλείπει το πεδίο
    // retain count = 0 → deinit
}

Σε αυτό το παράδειγμα φαίνεται πώς το ARC διαχειρίζεται τον αριθμητή: κατά την ανάθεση q = p, ο αριθμητής αυξάνει, καθώς το q εγκαταλείπει το πεδίο — μειώνεται. Όταν η τελευταία strong-αναφορά εξαφανιστεί, ο απαρχικοποιητής καλείται αμέσως. Κανένας garbage collector δεν περιμένει — η μνήμη απελευθερώνεται αμέσως.

ARC vs Garbage Collection: βασικές διαφορές

Το ARC και το Garbage Collection επιλύουν την ίδια εργασία — αυτόματη διαχείριση μνήμης — αλλά με ουσιαστικά διαφορετικές προσεγγίσεις. Η επιλογή μεταξύ τους καθορίζει την αρχιτεκτονική της γλώσσας: Swift (ARC) vs Java/Go (GC). Ας δούμε τις βασικές διαφορές.

ΧαρακτηριστικόARC (Swift/ObjC)GC (Java/Go)
Χρόνος απελευθέρωσηςΝτετερμινιστικός: αμέσως μετά το μηδενισμό του αριθμητήΜη ντετερμινιστικός: στην επόμενη συλλογή
Παύσεις εκτέλεσηςΚαμία (εισαγωγές retain/release στη φάση μεταγλώττισης)Υπάρχουν παύσεις Stop-The-World (2–200 ms)
Επιπλέον κόστοςΑύξηση/μείωση αριθμητή σε κάθε αναφοράΔιάσχιση γράφους αντικειμένων, σημείωση, απελευθέρωση
ΠροβλήματαRetain Cycle (χειροκινητική επίλυση)Κατακερματισμός heap, διαρροές σε ξεχασμένες αναφορές
Επιπλέον νήμαΔεν απαιτείταιΑπαιτείται νήμα garbage collector

Η βασική ανταλλαγή: το ARC παρέχει προβλεπτή διάρκεια ζωής αντικειμένων και μηδεμικές παύσεις, αλλά απαιτεί από τον προγραμματιστή κατανόηση του retain cycle και σωστή επιλογή weak/unowned. Το GC απαλλάσσει από αυτές τις ανησυχίες, αλλά με αντίτιμο τις μη ντετερμινιστικές παύσεις και ένα επιπλέον νήμα.

Strong, Weak και Unowned: προσδιοριστές αναφοράς στο ARC

Το ARC ορίζει τρεις τύπους προσδιοριστών αναφοράς, κάθε ένας από τους επηρεάζει διαφορετικά τον αριθμητή και τον κύκλο ζωής του αντικειμένου. Η σωστή επιλογή προσδιοριστή είναι η βάση της ασφαλούς εργασίας με τη μνήμη στο Swift.

Strong

Strong — ο προεπιλεγμένος προσδιοριστής. Κάθε strong-αναφορά αυξάνει το retain count του αντικειμένου κατά 1. Όσο υπάρχει τουλάχιστον μία strong-αναφορά, το αντικείμενο ζει. Όλες οι ιδιότητες κλάσεων και οι τοπικές μεταβλητές στο Swift είναι από προεπιλογή strong Οι strong-αναφορές δημιουργούν σχέση κυριότητας: το αντικείμενο A κατέχει το αντικείμενο B.

Weak

Weak — αναφορά που δεν αυξάνει το retain count. Το αντικείμενο μπορεί να απελευθερωθεί ακόμα και αν μια weak-αναφορά δείχνει σε αυτό. Μετά την απελευθέρωση, η weak-αναφορά ορίζεται αυτόματα σε nil. Οι weak-αναφορές δηλώνονται πάντα ως var με προαιρετικό τύπο (?). Χρησιμοποιούνται για να σπάσουν το retain cycle, ειδικά στο πρότυπο delegate.

Unowned

Unowned — μη ιδιοκτική αναφορά που, όπως και η weak, δεν αυξάνει το retain count. Ωστόσο, η unowned-αναφορά δεν ορίζεται σε nil μετά την απελευθέρωση — η πρόσβαση σε ένα απελευθερωμένο αντικείμενο προκαλεί crash. Το unowned χρησιμοποιείται όταν είναι εγγυημένο ότι το αντικείμενο ζει τουλάχιστον όσο και το αντικείμενο αναφοράς. Τυπικό σενάριο — closures και σχέσεις γονέα-παιδιού με εγγυημένη διάρκεια ζωής.

swift
class Customer {
    let name: String
    var card: CreditCard?         // strong
    init(name: String) { self.name = name }
    deinit { print("\(name) απελευθερώθηκε") }
}

class CreditCard {
    let number: String
    unowned let customer: Customer   // unowned — δεν κατέχει
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Κάρτα \(number) απελευθερώθηκε") }
}

var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer και CreditCard αμφότερα απελευθερώθηκαν — χωρίς retain cycle

Εδώ το CreditCard χρησιμοποιεί unowned-αναφορά στο Customer. Ο Customer κατέχει την κάρτα (strong), και η κάρτα δεν κατέχει τον πελάτη (unowned). Όταν ο Customer γίνεται nil, και τα δύο αντικείμενα απελευθερώνονται — δεν δημιουργείται retain cycle. Αν το card.customer ήταν strong, ο κύκλος θα είχε αποκλείσει την απελευθέρωση.

Τυπικά προβλήματα ARC και επίλυσή τους

Παρά την αυτοματοποίηση, το ARC δεν είναι πανάκεια. Οι προγραμματιστές αντιμετωπίζουν αρκετά τυπικά προβλήματα που απαιτούν κατανόηση του εσωτερικού μηχανισμού διαχείρισης μνήμης.

Retain Cycle σε Closures

Τα closures στο Swift συλλαμβάνουν εξωτερικές μεταβλητές μέσω strong-αναφοράς. Αν ένα closure ανατεθεί σε ιδιότητα κλάσης και συλλάβει το self — δημιουργείται retain cycle: η κλάση κρατάει το closure, το closure κρατάει το self. Λύση — capture list με weak ή unowned.

swift
class NetworkManager {
    var completionHandler: ((Data?) -> Void)?
    var data: Data?

    func fetchData() {
        completionHandler = { [weak self] result in
            guard let self else { return }
            self.data = result
            self.processResult()
        }
    }

    func processResult() { }
}

Η capture list [weak self] δημιουργεί μια weak-αναφορά στο self μέσα στο closure. Αυτό σπάει τον πιθανό retain cycle. Το guard let self εγγυάται ότι το αντικείμενο είναι ζωντανό πριν από την εκτέλεση του κώδικα. Το weak self — στανδαρική πρακτική για ασύγχρονα closures στο Swift.

Απόδοση retain/release

Αν και τα retain/release είναι ελαφριές λειτουργίες, οι συχνές αυξήσεις/μειώσεις του αριθμητή σε ζεστά σημεία προκαλούν επιπλέον κόστος. Στο Swift 5.9+, ο μεταγλωττιστής χρησιμοποιεί βελτιστοποίηση, κατά την οποία τα περιττά retain/release αφαιρούνται εάν ο αναλυτής αποδείξει την ασφάλεια. Ωστόσο, στο Objective-C τα retain/release μπορούν ακόμη να αποτελούν στενό σημείο σε σενάρια υψηλού φορτίου με εκατομμύρια κλήσεις ανά δευτερόλεπτο.

Autorelease Pool

Autorelease Pool — μηχανισμός καθυστερημένης απελευθέρωσης, που χρησιμοποιείται στο Objective-C και σε ορισμένα σενάρια Swift. Τα αντικείμενα τοποθετούνται σε μια ομάδα και λαμβάνουν release κατά την αποστράγγιση της ομάδας. Σε βρόχους με πολλά προσωρινά αντικείμενα (π.χ. ανάλυση JSON) η δημιουργία ιδιου autoreleasepool μειώνει την κορυφαία κατανάλωση της λειτουργικής μνήμης.

Συχνές Ερωτήσεις

Σε τι διαφέρει το ARC από τη χειροκινητική διαχείριση μνήμης (MRR);

Στη χειροκινητική διαχείριση (MRR), ο προγραμματιστής καλούσε ρητά τα retain, release και autorelease. Το ARC εισάγει αυτές τις κλήσεις αυτόματα στη φάση μεταγλώττισης, εξαλείφοντας τον κίνδυνο double-free, τις διαρροές λόγω ξεχασμένου release και τα σφάλματα εξισορρόπησης retain/release.

Μπορεί το ARC να λειτουργήσει με κώδικα C/C++;

Το ARC διαχειρίζεται μόνο αντικείμενα Objective-C και κλάσεις Swift. Για δομές και δείκτες C/C++, το ARC δεν εφαρμόζεται — αυτά τα αντικείμενα διαχειρίζονται χειροκινητικά ή μέσω εξύπνων δεικτών C++ (shared_ptr, unique_ptr). Τα αντικείμενα Core Foundation (CFString, CGColor) επίσης δεν εντάσσονται στο ARC.

Πότε να χρησιμοποιώ weak και πότε unowned;

weak — όταν το αντικείμενο μπορεί να απελευθερωθεί νρετε από το αντικείμενο αναφοράς (delegates, ασύγχρονα closures). unowned — όταν είναι εγγυημένο ότι το αντικείμενο ζει τουλάχιστον όσο το αντικείμενο αναφοράς (γονέας-παιδί, όπου το παιδί δεν μπορεί να υπάρξει χωρίς τον γονέα). Αν δεν είστε σίγουροι — επιλέξτε weak.

Τι είναι οι υπαρκτοί τύποι και πώς επηρεάζουν το ARC;

Οι υπαρκτοί τύποι (protocol as type) στο Swift συσκευάζουν την τιμή σε ένα ειδικό δοχείο (existential container). Αυτό αυξάνει τον αριθμό των retain/release στα όρια των πρωτοκόλλων. Στο Swift 5.7+, τα opaque result types και οι παράμετροι some μειώνουν το επιπλέον κόστος καταργώντας το δοχείο.

Πώς ελέγχω το retain count στο Swift;

Δεν υπάρχει άμεσο API για την ανάγνωση του retain count στο Swift — αυτό θεωρείται λεπτομέρεια υλοποίησης. Για διαγνωστική, χρησιμοποιήστε τα Instruments (Allocations, Leaks) ή το Memory Debugger στο Xcode. Αυτά τα εργαλεία δείχνουν τον αριθμό των ζωντανών παραδειγμάτων της κλάσης και τις αλυσίδες κράτησης.

Περίληψη

  • ARC — σύστημα διαχείρισης μνήμης μεταγλωττιστή για Swift και Objective-C μέσω μέτρησης αναφορών
  • Αρχή — κάθε αντικείμενο έχει retain count· στο μηδέν, το αντικείμενο απελευθερώνεται αμέσως και ντετερμινιστικά
  • Διαφορά από GC — το ARC λειτουργεί χωρίς νήμα φόντου και παύσεις Stop-The-World, αλλά απαιτεί έλεγχο retain cycle
  • Strong — αυξάνει τον αριθμητή· weak και unowned — δεν αυξάνουν, αλλά το unowned δεν μηδενίζεται κατά την απελευθέρωση
  • Closures — η κύρια αιτία retain cycle στο Swift· capture list [weak self] — στανδαρική λύση
  • Autorelease Pool — μηχανισμός καθυστερημένης απελευθέρωσης για προσωρινά αντικείμενα σε βρόχους και προσαρμοσμένα σενάρια
  • Διαγνωστική — Xcode Memory Debugger, Instruments και LeakCanary (μέσω ObjC bridge) για την εύρεση προβλημάτων

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης