Механизми идоракунии ёддоштӣ (ARC) дар забони Swift чӣ гуна кор мекунад?
sobes.tech AI
Ҷавоб аз AI
ARC (Автоматичне обчислення посилань) автоматично відстежує та керує посиланнями на екземпляри класів. Він звільняє пам’ять, зайняту екземпляром, коли на нього більше немає сильних посилань. ARC працює лише з екземплярами класів, а не з структурами або перерахуваннями, оскільки вони є типами-значеннями.
Три типи зв’язків між екземплярами:
- Strong (Сильна): Зв’язок, який збільшує лічильник посилань на екземпляр. За замовчуванням всі посилання є сильними.
- Weak (Слабка): Зв’язок, який не збільшує лічильник посилань. Використовується для запобігання циклам сильних посилань. Посилання типу
weakзавжди є опціональними, оскільки екземпляр може бути звільнений у будь-який момент. - Unowned (Безхазяйна): Зв’язок, який не збільшує лічильник посилань і використовується, коли гарантовано, що пов’язаний екземпляр буде існувати довше за поточний. Не обов’язково, але при спробі доступу до звільненого екземпляра виникає помилка виконання.
Цикли сильних посилань виникають, коли два або більше екземплярів класу мають сильні посилання один на одного, запобігаючи їх звільненню ARC. Для вирішення циклів використовуються weak або unowned посилання.
Приклад циклу сильних посилань:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // викликається при звільненні
print("\(name) звільняється")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // викликається при звільненні
print("Квартира \(unit) звільняється")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil // Нічого не виводиться, оскільки виник цикл сильних посилань
Рішення циклу сильних посилань за допомогою weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) звільняється")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Слабке посилання на Person
init(unit: String) {
self.unit = unit
}
deinit {
print("Квартира \(unit) звільняється")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Звільняє Person
unit4A = nil // Звільняє Apartment
Рішення циклу сильних посилань за допомогою unowned:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) звільняється")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Безхазяйне посилання на Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Карта #\(number) звільняється")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Звільняє Customer і CreditCard
ARC у замиканнях: Замикання також можуть створювати цикли посилань, захоплюючи екземпляри класів. Для запобігання використовуються списки захоплення ([weak self] або [unowned self]).
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy для можливості використовувати self до ініціалізації
[unowned self] in // список захоплення з "unowned self"
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) звільняється")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "привіт, світ")
print(paragraph!.asHTML())
paragraph = nil // Звільняє HTMLElement