Spec-Zone .ru
спецификации, руководства, описания, API

Библиотека разработчика XCode

Разработчик

Swift язык программирования

iBook
На этой странице

Автоматический подсчет ссылок

Swift использует Automatic Reference Counting (ARC), чтобы отследить и управлять использованием памяти Вашего приложения. В большинстве случаев это означает, что управление памятью “просто работает” в Swift, и Вы не должны думать об управлении памятью сами. Когда те экземпляры больше не необходимы, ARC автоматически высвобождает память, используемую экземплярами класса.

Однако в нескольких случаях ARC запрашивает больше информации об отношениях между частями Вашего кода для управления памятью для Вас. В этой главе описываются те ситуации и показывает, как Вы позволяете ARC управлять всей памятью своего приложения.

Как работы ARC

Каждый раз, когда Вы создаете новый экземпляр класса, ARC выделяет блок памяти, чтобы хранить информацию о том экземпляре. Эта память содержит информацию о типе экземпляра, вместе со значениями любых сохраненных свойств, связанных с тем экземпляром.

Кроме того, когда экземпляр больше не необходим, ARC высвобождает память, используемую тем экземпляром так, чтобы память могла использоваться для других целей вместо этого. Это гарантирует, чтобы экземпляры класса не занимали место в памяти, когда они больше не необходимы.

Однако, если ARC должен был освободить экземпляр, все еще использовавшийся, больше не будет возможно получить доступ к свойствам того экземпляра или вызвать методы того экземпляра. Действительно, если бы Вы попытались получить доступ к экземпляру, то Ваше приложение наиболее вероятно отказало бы.

Удостоверяться, что экземпляры не исчезают, в то время как они все еще необходимы, дорожки ARC, сколько свойств, констант и переменных в настоящее время относится к каждому экземпляру класса. ARC не освободит экземпляр, целая по крайней мере одна активная ссылка на тот экземпляр все еще существует.

Для создания этого возможным, каждый раз, когда Вы присваиваете экземпляр класса свойству, постоянному, или переменному, то свойство, постоянное, или переменное, делает сильную ссылку на экземпляр. Ссылку вызывают “сильной “ссылкой, потому что она сохраняет фирму, держатся, что экземпляр, и не позволяет ей быть освобожденной столько, сколько остается та сильная ссылка.

ARC в действии

Вот пример того, как работает Автоматический Подсчет ссылок. Этот пример запускается с простого вызванного класса Person, который определяет сохраненное постоянное вызванное свойство name:

  • class Person {
  • let name: String
  • init(name: String) {
  • self.name = name
  • println("\(name) is being initialized")
  • }
  • deinit {
  • println("\(name) is being deinitialized")
  • }
  • }

Person класс имеет инициализатор, устанавливающий экземпляр name свойство и печать сообщение, чтобы указать, что инициализация в стадии реализации. Person класс также имеет deinitializer, распечатывающий сообщение, когда освобожден экземпляр класса.

Следующий фрагмент кода определяет три переменные типа Person?, которые используются для установки многократных ссылок на новое Person экземпляр в последующих фрагментах кода. Поскольку эти переменные имеют дополнительный тип (Person?, нет Person), они автоматически инициализируются со значением nil, и в настоящее время не ссылайтесь на a Person экземпляр.

  • var reference1: Person?
  • var reference2: Person?
  • var reference3: Person?

Можно теперь создать новое Person экземпляр и присваивает его одной из этих трех переменных:

  • reference1 = Person(name: "John Appleseed")
  • // prints "John Appleseed is being initialized"

Обратите внимание на то, что сообщение "John Appleseed is being initialized" распечатан в точке, которую Вы вызываете Person инициализатор класса. Это подтверждает, что инициализация имела место.

Поскольку новое Person экземпляр был присвоен reference1 переменная, существует теперь сильная ссылка от reference1 к новому Person экземпляр. Поскольку существует по крайней мере одна сильная ссылка, ARC удостоверяется что это Person сохранен в памяти и не освобожден.

Если Вы присваиваете то же Person экземпляр к еще двум переменным, еще две сильных ссылки к тому экземпляру установлены:

  • reference2 = reference1
  • reference3 = reference1

Существует теперь три сильных ссылки к этому синглу Person экземпляр.

Если Вы повреждаете две из этих сильных ссылок (включая исходную ссылку) путем присвоения nil к двум из переменных единственная сильная ссылка остается, и Person экземпляр не освобожден:

  • reference1 = nil
  • reference2 = nil

ARC не освобождает Person экземпляр до третьей и заключительной сильной ссылки повреждается, в которой точке ясно, что Вы больше не используете Person экземпляр:

  • reference3 = nil
  • // prints "John Appleseed is being deinitialized"

Циклы сильной ссылки между экземплярами класса

В примерах выше, ARC в состоянии отследить число ссылок на новое Person экземпляр Вы создаете и освобождать это Person экземпляр, когда это больше не необходимо.

Однако возможно записать код, в котором экземпляр класса никогда не добирается до точки, где это имеет нулевые сильные ссылки. Это может произойти, если два экземпляра класса содержат сильную ссылку друг другу, такому, что каждый экземпляр поддерживает другой. Это известно как цикл сильной ссылки.

Вы разрешаете циклы сильной ссылки путем определения некоторых отношений между классами как слабые или ненаходящиеся в собственности ссылки вместо как сильные ссылки. Этот процесс описан в Разрешении Циклов Сильной ссылки Между Экземплярами класса. Однако перед изучением, как разрешить цикл сильной ссылки, полезно понять, как вызывается такой цикл.

Вот пример того, как цикл сильной ссылки может быть создан случайно. Этот пример определяет два вызванные класса Person и Apartment, которые моделируют блок квартир и его резидентных объектов:

  • class Person {
  • let name: String
  • init(name: String) { self.name = name }
  • var apartment: Apartment?
  • deinit { println("\(name) is being deinitialized") }
  • }
  • class Apartment {
  • let number: Int
  • init(number: Int) { self.number = number }
  • var tenant: Person?
  • deinit { println("Apartment #\(number) is being deinitialized") }
  • }

Каждый Person экземпляр имеет a name свойство типа String и дополнительное apartment свойство, которое является первоначально nil. apartment свойство является дополнительным, потому что у лица может не всегда быть квартиры.

Точно так же каждый Apartment экземпляр имеет a number свойство типа Int и имеет дополнительное tenant свойство, которое является первоначально nil. Свойство арендатора является дополнительным, потому что квартира может не всегда иметь арендатора.

Оба из этих классов также определяют deinitializer, распечатывающий факт, что экземпляр того класса является deinitialized. Это позволяет Вам видеть ли экземпляры Person и Apartment освобождаются как ожидалось.

Этот следующий фрагмент кода определяет две переменные дополнительного вызванного типа john и number73, который будет установлен в определенное Apartment и Person экземпляр ниже. Обе из этих переменных имеют начальное значение nil, на основании того, чтобы быть дополнительным:

  • var john: Person?
  • var number73: Apartment?

Можно теперь создать определенное Person экземпляр и Apartment экземпляр и присваивает эти новые экземпляры john и number73 переменные:

  • john = Person(name: "John Appleseed")
  • number73 = Apartment(number: 73)

Вот то, как сильные ссылки заботятся о создании и присвоении этих двух экземпляров. john переменная теперь имеет сильную ссылку к новому Person экземпляр, и number73 переменная имеет сильную ссылку к новому Apartment экземпляр:

image: ../Art/referenceCycle01_2x.png

Можно теперь соединить два экземпляра так, чтобы у лица была квартира, и квартира имеет арендатора. Обратите внимание на то, что восклицательный знак (!) используется, чтобы развернуть и получить доступ к экземплярам, сохраненным в john и number73 дополнительные переменные, так, чтобы могли быть установлены свойства тех экземпляров:

  • john!.apartment = number73
  • number73!.tenant = john

Вот то, как сильные ссылки заботятся о Вас, соединяют эти два экземпляра:

image: ../Art/referenceCycle02_2x.png

К сожалению, соединение этих двух экземпляров создает цикл сильной ссылки между ними. Person экземпляр теперь имеет сильную ссылку к Apartment экземпляр, и Apartment экземпляр имеет сильную ссылку к Person экземпляр. Поэтому, когда Вы повреждаете сильные ссылки, сохраненные john и number73 переменные, подсчеты ссылок не бросать! для обнуления, и экземпляры не освобождены ARC:

  • john = nil
  • number73 = nil

Обратите внимание на то, что ни один, deinitializer вызвали при установке этих двух переменных в nil. Цикл сильной ссылки предотвращает Person и Apartment экземпляры от того, чтобы когда-нибудь быть освобожденным, вызывая утечку памяти в Вашем приложении.

Вот то, как сильные ссылки заботятся о Вас, устанавливает john и number73 переменные к nil:

image: ../Art/referenceCycle03_2x.png

Сильные ссылки между Person экземпляр и Apartment экземпляр остается и не может быть поврежден.

Разрешение циклов сильной ссылки между экземплярами класса

Когда Вы работаете со свойствами типа класса, Swift обеспечивает два способа разрешить циклы сильной ссылки: слабые ссылки и ненаходящиеся в собственности ссылки.

Слабые и ненаходящиеся в собственности ссылки позволяют одному экземпляру в ссылочном цикле относиться к другому экземпляру, не сохраняя сильное, держат его. Экземпляры могут тогда относиться друг к другу, не создавая цикл сильной ссылки.

Используйте слабую ссылку каждый раз, когда это допустимо для той ссылки для становления nil в некоторый момент во время его времени жизни. С другой стороны используйте ненаходящуюся в собственности ссылку, когда Вы знаете, что ссылка никогда не будет nil как только это было установлено во время инициализации.

Слабые ссылки

Слабая ссылка является ссылкой, не сохраняющей сильное, держат экземпляр, который она отсылает к, и так не мешает ARC избавиться от экземпляра, на который ссылаются. Это поведение препятствует тому, чтобы ссылка стала частью цикла сильной ссылки. Вы указываете слабую ссылку путем размещения weak ключевое слово перед свойством или объявлением переменной.

Используйте слабую ссылку для предотвращения ссылочных циклов каждый раз, когда для той ссылки возможно не иметь “никакого значения” в некоторый момент в его жизни. Если ссылка будет всегда иметь значение, используйте ненаходящуюся в собственности ссылку вместо этого, как описано в Ненаходящихся в собственности Ссылках. В Apartment пример выше, для квартиры подходяще быть в состоянии не иметь “никакого арендатора” в некоторый момент в ее времени жизни, и таким образом, слабая ссылка является надлежащим способом повредить ссылочный цикл в этом случае.

Поскольку слабым ссылкам позволяют не иметь “никакого значения”, необходимо объявить каждую слабую ссылку как наличие дополнительного типа. Дополнительные типы являются предпочтительным способом представлять возможность для “никакого значения” в Swift.

Поскольку слабая ссылка не сохраняет сильное, держат экземпляр, к которому она относится, для того экземпляра возможно быть освобожденным, в то время как слабая ссылка все еще относится к ней. Поэтому ARC автоматически устанавливает слабую ссылку на nil когда освобожден экземпляр, к которому это относится. Можно проверить на существование значения в слабой ссылке, точно так же, как любое другое дополнительное значение, и Вы никогда не будете заканчивать со ссылкой на больше не существующий недопустимый экземпляр.

Пример ниже идентичен Person и Apartment пример сверху, с одним важным различием. На сей раз вокруг, Apartment тип tenant свойство объявляется как слабая ссылка:

  • class Person {
  • let name: String
  • init(name: String) { self.name = name }
  • var apartment: Apartment?
  • deinit { println("\(name) is being deinitialized") }
  • }
  • class Apartment {
  • let number: Int
  • init(number: Int) { self.number = number }
  • weak var tenant: Person?
  • deinit { println("Apartment #\(number) is being deinitialized") }
  • }

Сильные ссылки от этих двух переменных (john и number73) и ссылки между этими двумя экземплярами создаются как прежде:

  • var john: Person?
  • var number73: Apartment?
  • john = Person(name: "John Appleseed")
  • number73 = Apartment(number: 73)
  • john!.apartment = number73
  • number73!.tenant = john

Вот то, как ссылки смотрят теперь, когда Вы соединили эти два экземпляра:

image: ../Art/weakReference01_2x.png

Person экземпляр все еще имеет сильную ссылку к Apartment экземпляр, но Apartment экземпляр теперь имеет слабую ссылку на Person экземпляр. Это означает это при повреждении сильной ссылки, сохраненной john переменные, больше нет сильных ссылок к Person экземпляр:

image: ../Art/weakReference02_2x.png

Поскольку больше нет сильных ссылок к Person экземпляр, это освобождено:

  • john = nil
  • // prints "John Appleseed is being deinitialized"

Единственная остающаяся сильная ссылка к Apartment экземпляр от number73 переменная. При повреждении той сильной ссылки больше нет сильных ссылок к Apartment экземпляр:

image: ../Art/weakReference03_2x.png

Поскольку больше нет сильных ссылок к Apartment экземпляр, это также освобождено:

  • number73 = nil
  • // prints "Apartment #73 is being deinitialized"

Заключительные два фрагмента кода выше шоу, что deinitializers для Person экземпляр и Apartment печать экземпляра их сообщения «deinitialized» после john и number73 переменные установлены в nil. Это доказывает, что был поврежден ссылочный цикл.

Ненаходящиеся в собственности ссылки

Как слабые ссылки, ненаходящаяся в собственности ссылка не сохраняет сильное, держат экземпляр, к которому она относится. В отличие от слабой ссылки, однако, ненаходящаяся в собственности ссылка, как предполагается, всегда имеет значение. Из-за этого ненаходящаяся в собственности ссылка всегда определяется как обязательный тип. Вы указываете ненаходящуюся в собственности ссылку путем размещения unowned ключевое слово перед свойством или объявлением переменной.

Поскольку ненаходящаяся в собственности ссылка является обязательной, Вы не должны разворачивать ненаходящуюся в собственности ссылку каждый раз, когда это используется. К ненаходящейся в собственности ссылке можно всегда получать доступ непосредственно. Однако ARC не может установить ссылку на nil когда экземпляр, к которому это относится, освобожден, потому что переменные обязательного типа не могут быть установлены в nil.

Следующий пример определяет два класса, Customer и CreditCard, которые моделируют клиента банка и возможную кредитную карту для того клиента. Эти два класса каждое хранилище экземпляр другого класса как свойство. Это отношение имеет потенциал для создания цикла сильной ссылки.

Отношение между Customer и CreditCard немного отличается от отношения между Apartment и Person замеченный в примере слабой ссылки выше. В этой модели данных клиент может или может не иметь кредитной карты, но кредитная карта будет всегда связываться с клиентом. Представлять это, Customer класс имеет дополнительное card свойство, но CreditCard класс имеет обязательное customer свойство.

Кроме того, новое CreditCard экземпляр может только быть создан путем передачи a number значение и a customer экземпляр к пользовательскому CreditCard инициализатор. Это гарантирует этому a CreditCard экземпляр всегда имеет a customer экземпляр связался с ним когда CreditCard экземпляр создается.

Поскольку кредитная карта будет всегда иметь клиента, Вы определяете customer свойство как ненаходящаяся в собственности ссылка, для предотвращения цикла сильной ссылки:

  • class Customer {
  • let name: String
  • var card: CreditCard?
  • init(name: String) {
  • self.name = name
  • }
  • deinit { println("\(name) is being deinitialized") }
  • }
  • class CreditCard {
  • let number: UInt64
  • unowned let customer: Customer
  • init(number: UInt64, customer: Customer) {
  • self.number = number
  • self.customer = customer
  • }
  • deinit { println("Card #\(number) is being deinitialized") }
  • }

Этот следующий фрагмент кода определяет дополнительное Customer переменную вызывают john, который будет использоваться для хранения ссылки на определенного клиента. Эта переменная имеет начальное значение ноля, на основании того, чтобы быть дополнительным:

  • var john: Customer?

Можно теперь создать a Customer экземпляр и использование это, чтобы инициализировать и присвоить новое CreditCard экземпляр как тот клиент card свойство:

  • john = Customer(name: "John Appleseed")
  • john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

Вот то, как ссылки смотрят, теперь, когда Вы соединили эти два экземпляра:

image: ../Art/unownedReference01_2x.png

Customer экземпляр теперь имеет сильную ссылку к CreditCard экземпляр, и CreditCard экземпляр имеет ненаходящуюся в собственности ссылку на Customer экземпляр.

Из-за ненаходящегося в собственности customer ссылка, когда Вы повреждаете сильную ссылку, сохраненную john переменная, больше нет сильных ссылок к Customer экземпляр:

image: ../Art/unownedReference02_2x.png

Поскольку больше нет сильных ссылок к Customer экземпляр, это освобождено. После того, как это происходит, больше нет сильных ссылок к CreditCard экземпляр, и это также освобождено:

  • john = nil
  • // prints "John Appleseed is being deinitialized"
  • // prints "Card #1234567890123456 is being deinitialized"

Заключительный фрагмент кода выше шоу, что deinitializers для Customer экземпляр и CreditCard экземпляр оба распечатывает их сообщения «deinitialized» после john переменная установлена в nil.

Ненаходящиеся в собственности ссылки и неявно развернутые дополнительные свойства

Примеры для слабых и ненаходящихся в собственности ссылок выше покрывают два из более общих сценариев, в которых необходимо повредить цикл сильной ссылки.

Person и Apartment пример показывает ситуацию, где два свойства, обоим из которых позволяют быть nil, имейте потенциал для порождения цикла сильной ссылки. Этот сценарий лучше всего разрешен со слабой ссылкой.

Customer и CreditCard пример показывает ситуацию, где одно свойство, которому позволяют быть nil и другое свойство, которое не может быть nil имейте потенциал для порождения цикла сильной ссылки. Этот сценарий лучше всего разрешен с ненаходящейся в собственности ссылкой.

Однако существует третий сценарий, в котором оба свойства должны всегда иметь значение, и никакое свойство никогда не должно быть nil как только инициализация завершена. В этом сценарии полезно объединить ненаходящееся в собственности свойство на одном классе с неявно развернутым дополнительным свойством на другом классе.

Это позволяет обоим свойствам быть полученными доступ непосредственно (без дополнительного разворачивания), как только инициализация завершена, все еще избегая ссылочного цикла. Этот раздел показывает Вам, как установить такое отношение.

Пример ниже определяет два класса, Country и City, каждый из которых хранит экземпляр другого класса как свойство. В этой модели данных каждая страна должна всегда иметь столицу, и каждый город должен всегда принадлежать стране. Представлять это, Country класс имеет a capitalCity свойство, и City класс имеет a country свойство:

  • class Country {
  • let name: String
  • let capitalCity: City!
  • init(name: String, capitalName: String) {
  • self.name = name
  • self.capitalCity = City(name: capitalName, country: self)
  • }
  • }
  • class City {
  • let name: String
  • unowned let country: Country
  • init(name: String, country: Country) {
  • self.name = name
  • self.country = country
  • }
  • }

Устанавливать взаимозависимость между этими двумя классами, инициализатором для City берет a Country экземпляр и хранилища этот экземпляр в country свойство.

Инициализатор для City вызывается из инициализатора для Country. Однако инициализатор для Country не может передать self к City инициализатор до нового Country экземпляр полностью инициализируется, как описано в Двухфазной Инициализации.

Для разрешения с этим требованием Вы объявляете capitalCity свойство Country как неявно развернутое дополнительное свойство, обозначенное восклицательным знаком в конце его аннотации типа (City!). Это означает что capitalCity свойство имеет значение по умолчанию nil, как любой другой дополнительный, но может быть получен доступ без потребности развернуть ее значение, как описано в Неявно Развернутом Optionals.

Поскольку capitalCity имеет значение по умолчанию nil значение, новое Country экземпляр считают полностью инициализированным как только Country экземпляр устанавливает name свойство в его инициализаторе. Это означает что Country инициализатор может начать ссылаться и раздавать неявное self свойство, как только name свойство установлено. Country инициализатор может поэтому передать self как один из параметров для City инициализатор, когда Country инициализатор устанавливает свое собственное capitalCity свойство.

Все это означает, что можно создать Country и City экземпляры в отдельном операторе, не создавая цикл сильной ссылки, и capitalCity к свойству можно получить доступ непосредственно, не будучи должен использовать восклицательный знак для разворачивания его дополнительного значения:

  • var country = Country(name: "Canada", capitalName: "Ottawa")
  • println("\(country.name)'s capital city is called \(country.capitalCity.name)")
  • // prints "Canada's capital city is called Ottawa"

В примере выше, использование неявно развернутого дополнительный означает, что удовлетворены все двухфазные требования инициализатора класса. capitalCity свойство может использоваться и получаться доступ как обязательное значение, как только инициализация завершена, все еще избегая цикла сильной ссылки.

Циклы сильной ссылки для закрытий

Вы видели выше, как цикл сильной ссылки может быть создан, когда два свойства экземпляра класса содержат сильную ссылку друг другу. Вы также видели, как использовать слабые и ненаходящиеся в собственности ссылки для повреждения этих циклов сильной ссылки.

Цикл сильной ссылки может также произойти, если Вы присваиваете закрытие свойству экземпляра класса, и организация того закрытия получает экземпляр. Это получение могло бы произойти, потому что организация закрытия получает доступ к свойству экземпляра, такой как self.someProperty, или потому что закрытие вызывает метод на экземпляре, такой как self.someMethod(). В любом случае эти доступы заставляют закрытие «получать» self, создание цикла сильной ссылки.

Этот цикл сильной ссылки происходит, потому что закрытия, как классы, являются ссылочными типами. При присвоении закрытия свойству Вы присваиваете ссылку на то закрытие. В сущности это - та же проблема как выше — две сильных ссылки поддерживают друг друга. Однако, а не два экземпляра класса, на сей раз это - экземпляр класса и закрытие, поддерживающие друг друга.

Swift предоставляет изящное решение этой проблемы, известной как список получения закрытия. Однако перед изучением, как повредить цикл сильной ссылки со списком получения закрытия, полезно понять, как может быть вызван такой цикл.

Пример ниже шоу, как можно создать цикл сильной ссылки при использовании закрытия, на которое это ссылается self. Этот пример определяет вызванный класс HTMLElement, который обеспечивает простую модель для отдельного элемента в документе HTML:

  • class HTMLElement {
  • let name: String
  • let text: String?
  • lazy var asHTML: () -> String = {
  • 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 {
  • println("\(name) is being deinitialized")
  • }
  • }

HTMLElement класс определяет a name свойство, указывающее имя элемента, такой как "p" для элемента абзаца, или "br" для элемента разрыва строки. HTMLElement также определяет дополнительное text свойство, которое можно установить в строку, представляющую текст, который будет представлен в том элементе HTML.

В дополнение к этим двум простым свойствам, HTMLElement класс определяет ленивое вызванное свойство asHTML. Это свойство ссылается на объединяющееся закрытие name и text в HTML представляют фрагмент в виде строки. asHTML свойство имеет тип () -> String, или “функция, не берущая параметров и возвращающая a String значение”.

По умолчанию, asHTML свойство присваивается закрытие, возвращающее строковое представление HTML-тэга. Этот тег содержит дополнительное text оцените, если это существует, или никакое текстовое содержание если text не существует. Для элемента абзаца возвратилось бы закрытие "<p>some text</p>" или "<p />", В зависимости от ли text свойство равняется "some text" или nil.

asHTML свойство называют и используют несколько как метод экземпляра. Однако, потому что asHTML свойство закрытия, а не метод экземпляра, можно заменить значение по умолчанию asHTML свойство с пользовательским закрытием, если Вы хотите изменить рендеринг HTML для определенного элемента HTML.

HTMLElement класс обеспечивает единственный инициализатор, берущий a name параметр и (при желании) a text параметр для инициализации нового элемента. Класс также определяет deinitializer, распечатывающий сообщение для показа когда HTMLElement экземпляр освобожден.

Вот то, как Вы используете HTMLElement класс, чтобы создать и распечатать новый экземпляр:

  • var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
  • println(paragraph!.asHTML())
  • // prints "<p>hello, world</p>"

К сожалению, HTMLElement класс, как записано выше, создает цикл сильной ссылки между HTMLElement экземпляр и закрытие используются для его значения по умолчанию asHTML значение. Вот то, как смотрит цикл:

image: ../Art/closureReferenceCycle01_2x.png

Экземпляр asHTML свойство содержит сильную ссылку к своему закрытию. Однако, потому что закрытие относится к self в его организации (как способ сослаться self.name и self.text), закрытие получает сам, что означает, что оно сдерживает сильную ссылку к HTMLElement экземпляр. Цикл сильной ссылки создается между двумя. (Для получения дополнительной информации о получении значений в закрытии, посмотрите Значения Получения.)

Если Вы устанавливаете paragraph переменная к nil и повредите его сильную ссылку к HTMLElement экземпляр, ни один HTMLElement экземпляр, ни его закрытие освобождены из-за цикла сильной ссылки:

  • paragraph = nil

Обратите внимание на то, что сообщение в HTMLElement deinitializer не распечатан, который показывает что HTMLElement экземпляр не освобожден.

Разрешение циклов сильной ссылки для закрытий

Вы разрешаете цикл сильной ссылки между закрытием и экземпляром класса путем определения списка получения как части определения закрытия. Список получения определяет правила использовать при получении один или несколько ссылочные типы в организации закрытия. Как с циклами сильной ссылки между двумя экземплярами класса, Вы объявляете, что каждая полученная ссылка слабая или ненаходящаяся в собственности ссылка, а не сильная ссылка. Надлежащий выбор слабых или ненаходящихся в собственности зависит от отношений между различными частями Вашего кода.

Определение списка получения

Каждый элемент в списке получения является соединением weak или unowned ключевое слово со ссылкой на экземпляр класса (такой как self) или переменная, инициализированная с некоторым значением (такой как delegate = self.delegate!). Эти соединения записаны в паре квадратных скобок, разделенных запятыми.

Поместите список получения перед списком параметров закрытия и типом возврата, если им предоставлены:

  • lazy var someClosure: (Int, String) -> String = {
  • [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
  • // closure body goes here
  • }

Если закрытие не указывает список параметров или возвращает тип, потому что они могут быть выведены из контекста, поместить, список получения в очень запускаются закрытия, сопровождаемого in ключевое слово:

  • lazy var someClosure: () -> String = {
  • [unowned self, weak delegate = self.delegate!] in
  • // closure body goes here
  • }

Слабые и ненаходящиеся в собственности ссылки

Определите получение в закрытии как ненаходящаяся в собственности ссылка, когда закрытие и экземпляр, который это получает, будут всегда относиться друг к другу и будут всегда освобождаться одновременно.

С другой стороны определите получение как слабую ссылку, когда полученная ссылка сможет стать nil в некоторый момент в будущем. Слабые ссылки всегда имеют дополнительный тип, и автоматически становятся nil . Когда экземпляр, на который они ссылаются освобожден, это позволяет Вам проверить на их существование в организации закрытия.

Ненаходящаяся в собственности ссылка является надлежащим методом получения для использования для разрешения цикла сильной ссылки в HTMLElement пример от ранее. Вот то, как Вы пишете HTMLElement класс для предотвращения цикла:

  • class HTMLElement {
  • let name: String
  • let text: String?
  • lazy var asHTML: () -> String = {
  • [unowned self] in
  • 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 {
  • println("\(name) is being deinitialized")
  • }
  • }

Эта реализация HTMLElement идентично предыдущей реализации, кроме добавления списка получения в asHTML закрытие. В этом случае список получения [unowned self], что означает “получение сам как ненаходящаяся в собственности ссылка, а не сильная ссылка”.

Можно создать и распечатать HTMLElement экземпляр как прежде:

  • var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
  • println(paragraph!.asHTML())
  • // prints "<p>hello, world</p>"

Вот то, как ссылки смотрят со списком получения на месте:

image: ../Art/closureReferenceCycle02_2x.png

На сей раз, получение self закрытием ненаходящаяся в собственности ссылка и не сохраняет сильное, держатся HTMLElement экземпляр это получило. Если Вы устанавливаете сильную ссылку от paragraph переменная к nil, HTMLElement экземпляр освобожден, как видно из печати его сообщения deinitializer в примере ниже:

  • paragraph = nil
  • // prints "p is being deinitialized"