Middle
Μιλήστε μας για τη διαχείριση μνήμης στο iOS.
sobes.tech AI
Απάντηση από AI
Το iOS χρησιμοποιεί αυτόματη μέτρηση αναφορών (ARC) για τη διαχείριση μνήμης. Το ARC απελευθερώνει αυτόματα αντικείμενα μόλις σταματούν να αναφέρονται σε αυτά.
Βασικές έννοιες:
- Ισχυρή Αναφορά: Αυξάνει τον μετρητή αναφορών ενός αντικειμένου. Το αντικείμενο δεν θα απελευθερωθεί όσο υπάρχουν ισχυρές αναφορές σε αυτό.
- Αδύναμη Αναφορά: Δεν αυξάνει τον μετρητή αναφορών. Χρησιμοποιείται για την αποφυγή κυκλωμάτων ισχυρών αναφορών. Αναφέρεται σε ένα αντικείμενο που μπορεί να απελευθερωθεί. Αν το αντικείμενο απελευθερωθεί, η αδύναμη αναφορά γίνεται
nil. - Ανεξάρτητη Αναφορά (unowned): Παρόμοια με την αδύναμη, δεν αυξάνει τον μετρητή αναφορών. Χρησιμοποιείται όταν το αντικείμενο στο οποίο αναφέρεται έχει την ίδια ή μεγαλύτερη διάρκεια ζωής. Η ανεξάρτητη αναφορά δεν γίνεται
nilόταν το αντικείμενο απελευθερώνεται. Η πρόσβαση σε ένα απελευθερωμένο αντικείμενο μέσω ανεξάρτητης αναφοράς προκαλεί σφάλμα εκτέλεσης.
Κύκλοι ισχυρών αναφορών (Retain Cycles): Προκύπτουν όταν δύο ή περισσότερα αντικείμενα έχουν ισχυρές αναφορές το ένα στο άλλο, εμποδίζοντας την απελευθέρωσή τους. Λύνονται με αδύναμες ή ανεξάρτητες αναφορές.
Παράδειγμα κύκλου ισχυρών αναφορών και η λύση του:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) αρχικοποιείται")
}
deinit {
print("\(name) απελευθερώνεται")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Χρησιμοποιεί αδύναμη αναφορά για να αποτρέψει κύκλο
init(unit: String) {
self.unit = unit
print("Δωμάτιο \(unit) αρχικοποιείται")
}
deinit {
print("Δωμάτιο \(unit) απελευθερώνεται")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john // Εδώ δημιουργείται κύκλος
john = nil
unit4A = nil
// Οι μέθοδοι deinit δεν καλούνται λόγω κύκλου
Λύση με weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) αρχικοποιείται")
}
deinit {
print("\(name) απελευθερώνεται")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Χρησιμοποιεί αδύναμη αναφορά για να αποτρέψει κύκλο
init(unit: String) {
self.unit = unit
print("Δωμάτιο \(unit) αρχικοποιείται")
}
deinit {
print("Δωμάτιο \(unit) απελευθερώνεται")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Και τα δύο αντικείμενα απελευθερώνονται σωστά
Διαφορά μεταξύ unowned και weak:
- Χρησιμοποιήστε
weakόταν η αναφορά μπορεί να γίνειnil(το αντικείμενο μπορεί να απελευθερωθεί πρώτο). - Χρησιμοποιήστε
unownedόταν η αναφορά πάντα θα έχει τιμή (το αντικείμενο στο οποίο αναφέρεται έχει την ίδια ή μεγαλύτερη διάρκεια ζωής).
Closures και κύκλοι αναφορών:
Οι closures μπορούν να καταγράψουν αναφορές σε αντικείμενα, δημιουργώντας κύκλους ισχυρών αναφορών. Αυτό λύνεται με λίστα καταγραφής (capture list).
Παράδειγμα:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[weak self] in // Καταγραφή `self` αδύναμη
guard let self = self else {
return ""
}
var html = "<\(self.name)"
if let text = self.text {
html += ">\(text)</\(self.name)>"
} else {
html += " />"
}
return html
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) απελευθερώνεται")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil
// Το αντικείμενο απελευθερώνεται
Αποσφαλμάτωση μνήμης:
- Memory Graph Debugger: Στο Xcode, οπτικοποιεί τις συνδέσεις μεταξύ αντικειμένων και εντοπίζει κύκλους ισχυρών αναφορών.
- Instruments (Allocations, Leaks): Εργαλεία για την παρακολούθηση της κατανομής και απελευθέρωσης μνήμης, και την ανίχνευση διαρροών.