Sobes.tech
Middle

Τι είναι η αυτόματη καταμέτρηση συνδέσμων;

sobes.tech AI

Απάντηση από AI

Ο αυτόματος υπολογισμός αναφορών (Automatic Reference Counting, ARC) είναι ένας μηχανισμός διαχείρισης μνήμης στα Swift και Objective-C, ο οποίος παρακολουθεί και απελευθερώνει αυτόματα τη μνήμη που έχει εκχωρηθεί για αντικείμενα. Κάθε αντικείμενο κλάσης έχει έναν μετρητή αναφορών, ο οποίος αυξάνεται κατά τη δημιουργία μιας ισχυρής αναφοράς σε αυτό και μειώνεται κατά την διαγραφή της. Όταν ο μετρητής αναφορών φτάσει το μηδέν, το ARC αυτόματα απελευθερώνει το αντικείμενο και τη μνήμη που καταλαμβάνει.

Το ARC αποτρέπει διαρροές μνήμης και διπλή απελευθέρωση, απλοποιώντας τη διαχείριση μνήμης σε σύγκριση με την χειροκίνητη διαχείριση (όπως στο Objective-C χωρίς ARC).

Υπάρχουν τρεις τύποι αναφορών:

  1. Strong (Ισχυρή): Αυξάνει τον μετρητή αναφορών του αντικειμένου. Είναι ο προεπιλεγμένος τύπος αναφοράς.
  2. Weak (Αδύναμη): Δεν αυξάνει τον μετρητή αναφορών. Χρησιμοποιείται για την αποτροπή κύκλων ισχυρών αναφορών, όταν δύο αντικείμενα αναφέρονται το ένα στο άλλο. Μια αδύναμη αναφορά γίνεται nil αν το αντικείμενο στο οποίο αναφέρεται διαγραφεί. Ορίζεται με τη λέξη-κλειδί weak.
  3. Unowned (Ανεξάρτητη): Δεν αυξάνει τον μετρητή αναφορών και πάντα έχει μια τιμή. Χρησιμοποιείται όταν είναι γνωστό ότι η αναφορά θα δείχνει πάντα σε ένα αντικείμενο όσο αυτό υπάρχει. Σε αντίθεση με το weak, η ανεξάρτητη αναφορά δεν γίνεται nil και μπορεί να προκαλέσει σφάλμα αν προσπαθήσετε να αποκτήσετε πρόσβαση σε αντικείμενο μετά τη διαγραφή του. Ορίζεται με τη λέξη-κλειδί unowned.

Παράδειγμα κύκλου ισχυρών αναφορών:

class Human {
    let name: String
    var apartment: Apartment? // Ισχυρή αναφορά σε προαιρετικό Apartment
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    var tenant: Human? // Ισχυρή αναφορά σε προαιρετικό Human
    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) is being initialized")
    }
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

var john: Human?
var unit4A: Apartment?

john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
// Ούτε "John Appleseed is being deinitialized" ούτε "Apartment 4A is being deinitialized" θα εμφανιστούν λόγω του κύκλου ισχυρών αναφορών

Λύση του προβλήματος κύκλου ισχυρών αναφορών με χρήση του weak:

class Human {
    let name: String
    var apartment: Apartment?
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Human? // Αδύναμη αναφορά
    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) is being initialized")
    }
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

var john: Human?
var unit4A: Apartment?

john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil // Ο John διαγράφεται, καθώς ο μετρητής αναφορών του γίνεται 0
unit4A = nil // Το διαμέρισμα διαγράφεται, καθώς ο μετρητής αναφορών του γίνεται 0