Поиск…


Вступление

В этом разделе описывается, как и когда среда выполнения Swift должна выделять память для структур данных приложений и когда эта память должна быть восстановлена. По умолчанию экземпляры класса поддержки памяти управляются посредством подсчета ссылок. Структуры всегда передаются путем копирования. Чтобы отказаться от схемы управления встроенной памятью, можно использовать структуру [ 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-интерфейсы всегда будут предпочтительнее.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow