Что такое автоматический подсчет ссылок?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Автоматический подсчет ссылок (Automatic Reference Counting, ARC) - это механизм управления памятью в Swift и Objective-C, который автоматически отслеживает и освобождает память, выделенную для объектов. Каждый экземпляр класса имеет счетчик ссылок, который увеличивается при создании сильной ссылки на объект и уменьшается при ее удалении. Когда счетчик ссылок достигает нуля, ARC автоматически деаллоцирует объект и освобождает занимаемую им память.
ARC предотвращает утечки памяти и двойное освобождение, упрощая управление памятью по сравнению с ручным управлением (как в Objective-C без ARC).
Существует три типа ссылок:
- Strong (Сильная): Увеличивает счетчик ссылок объекта. Является типом ссылки по умолчанию.
- Weak (Слабая): Не увеличивает счетчик ссылок. Используется для предотвращения циклов сильных ссылок, когда два объекта сильно ссылаются друг на друга. Слабая ссылка становится
nil, если объект, на который она указывает, деаллоцирован. Определяется с помощью ключевого словаweak. - Unowned (Бесхозная): Не увеличивает счетчик ссылок и всегда имеет значение. Используется, когда известно, что ссылка всегда будет указывать на объект, пока объект существует. В отличие от
weak, бесхозная ссылка не становитсяnilи может вызвать сбой, если попытаться получить доступ к объекту после его деаллокации. Определяется с помощью ключевого словаunowned.
Пример цикла сильных ссылок:
class Human {
let name: String
var apartment: Apartment? // Сильная ссылка на Optional 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? // Сильная ссылка на Optional 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 // Apartment деаллоцируется, так как его счетчик ссылок становится 0