Sobes.tech
Middle

Πώς μπορεί να αποτραπεί ο κύκλος διατήρησης (retain cycle) στο iOS;

sobes.tech AI

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

Οι κύκλοι διατήρησης αποτρέπονται με τη σωστή χρήση των αδύναμων (weak) ή ανεξάρτητων (unowned) αναφορών.

Αδύναμες αναφορές (weak):

  • Δεν αυξάνουν τον μετρητή αναφορών του αντικειμένου.
  • Μπορούν να γίνουν nil (nullable).
  • Χρησιμοποιούνται όταν ένα αντικείμενο μπορεί να υπάρχει ανεξάρτητα από ένα άλλο (π.χ., ένας delegate).
class DelegateExample {
    weak var delegate: SomeDelegateType? // Αδύναμη αναφορά στον delegate
}

Ανεξάρτητες αναφορές (unowned):

  • Δεν αυξάνουν τον μετρητή αναφορών του αντικειμένου.
  • Είναι εγγυημένα μη nil.
  • Χρησιμοποιούνται όταν ένα αντικείμενο κατέχει ρητά ένα άλλο, αλλά το εξαρτώμενο αντικείμενο μπορεί να υπάρχει μόνο μαζί με τον ιδιοκτήτη (π.χ., closures που καταγράφουν το self σε μια κλάση, όπου η closure "ανήκει" ρητά στην περίπτωση της κλάσης). Η πρόσβαση σε μια unowned αναφορά όταν το αντικείμενο έχει ήδη απελευθερωθεί θα προκαλέσει σφάλμα κατά την εκτέλεση.
class Owner {
    var closure: (() -> Void)?

    func setupClosure() {
        closure = { [unowned self] in // Ανεξάρτητη `unowned` αναφορά στο self
            // Χρήση του self
            print("Χρήση `unowned` self")
        }
    }
}

Χρήση σε closures: Οι closures μπορούν να δημιουργήσουν κύκλους διατήρησης αν καταγράφουν στιγμιότυπα κλάσεων με ισχυρές αναφορές, και αυτό το στιγμιότυπο κλάσης περιέχει επίσης μια ισχυρή αναφορά στο closure. Για να το αποτρέψετε αυτό, χρησιμοποιούνται λίστες καταγραφής (capture lists) στην αρχή του closure:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [weak self] in // Αδύναμη αναφορά στο self
        guard let strongSelf = self else {
            return "" // Διαχείριση της περίπτωσης όπου το self είναι ήδη nil
        }
        if let text = strongSelf.text {
            return "<\(strongSelf.name)>\(text)</\(strongSelf.name)>"
        } else {
            return "<\(strongSelf.name)/>"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) αποδεσμεύεται")
    }
}

Η επιλογή μεταξύ weak και unowned εξαρτάται από τη σημασιολογία των σχέσεων μεταξύ των αντικειμένων:

  • weak: όταν η αναφορά μπορεί να γίνει nil κατά τη διάρκεια του κύκλου ζωής του αντικειμένου στο οποίο αναφέρεται.
  • unowned: όταν το αντικείμενο στο οποίο αναφέρεται υπάρχει εγγυημένα περισσότερο ή ίσο χρόνο με το αντικείμενο που το αναφέρει, και η αναφορά ποτέ δεν θα γίνει nil.