Swift Language
Управление памятью
Поиск…
Вступление
Unmanaged
] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged
замечания
Когда использовать слабое ключевое слово:
Следует использоватьweak
ключевое слово, если ссылочный объект может быть освобожден за время жизни объекта, содержащего ссылку. Когда использовать ключевое слово unowned:
unowned
-ключевое слово следует использовать, если объект ссылки не ожидается освобождаться в течение всего срока службы объекта , держащий ссылку. Ловушки
Частая ошибка заключается в том, чтобы забыть создавать ссылки на объекты, которые должны жить после завершения функции, например, менеджеров местоположения, менеджеров движения и т. Д.Пример:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Этот пример не будет работать должным образом, так как менеджер местоположений освобождается после возвращения инициализатора. Правильное решение - создать сильную ссылку в качестве переменной экземпляра:
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Справочные циклы и слабые ссылки
Базовый цикл (или цикл сохранения ) назван так потому, что он указывает цикл в графе объектов :
Каждая стрелка указывает, что один объект сохраняет другую (сильная ссылка). Если цикл не сломан, память для этих объектов никогда не будет освобождена .
Цикл сохранения создается, когда два экземпляра классов ссылаются друг на друга:
class A { var b: B? = nil }
class B { var a: A? = nil }
let a = A()
let b = B()
a.b = b // a retains b
b.a = a // b retains a -- a reference cycle
Оба экземпляра они будут жить до тех пор, пока программа не завершится. Это цикл сохранения.
Слабые ссылки
Чтобы избежать циклов сохранения, используйте ключевое слово weak
или unowned
при создании ссылок для прерывания циклов сохранения.
class B { weak var a: A? = nil }
Слабые или неопубликованные ссылки не будут увеличивать количество ссылок экземпляра. Эти ссылки не способствуют сохранению циклов. Слабая ссылка становится nil
когда ссылающийся на нее объект освобождается.
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
При работе с затворами вы также можете использовать weak
и unowned
списки захвата .
Управление памятью вручную
При взаимодействии с API-интерфейсом C можно отменить контрольный счетчик Swift. Это достигается с помощью неуправляемых объектов.
Если вам нужно указать указатель типа на функцию C, используйте метод toOpaque
Unmanaged
структуры для получения необработанного указателя и fromOpaque
для восстановления исходного экземпляра:
setupDisplayLink() {
let pointerToSelf: UnsafeRawPointer = Unmanaged.passUnretained(self).toOpaque()
CVDisplayLinkSetOutputCallback(self.displayLink, self.redraw, pointerToSelf)
}
func redraw(pointerToSelf: UnsafeRawPointer, /* args omitted */) {
let recoveredSelf = Unmanaged<Self>.fromOpaque(pointerToSelf).takeUnretainedValue()
recoveredSelf.doRedraw()
}
Обратите внимание: если вы используете passUnretained
и аналоги, необходимо принять все меры предосторожности, как в случае с unowned
ссылками.
Чтобы взаимодействовать с устаревшими API Objective-C, можно было бы вручную повлиять на подсчет ссылок на определенный объект. Для этого Unmanaged
имеет соответствующие методы retain
и release
. Тем не менее, более желательно использовать passRetained
и takeRetainedValue
, которые выполняют сохранение перед возвратом результата:
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
Эти решения всегда должны быть в последнюю очередь, и языковые API-интерфейсы всегда будут предпочтительнее.