Qual é a diferença entre uma referência fraca e uma referência sem dono?

Swift tem:

  • Referências Fortes
  • Referências fracas
  • Referências Não Conhecidas

Como uma referência sem dono é diferente de uma referência fraca?

Quando é seguro usar uma referência sem dono?

As referências sem dono são um risco de segurança, como pointers pendentes em C / C ++?

   

As referências weak e unowned não criam um strong controle sobre o object referido (ou seja, elas não aumentam a contagem de retenções para evitar que a ARC desaloque o object referido).

Mas por que duas palavras-chave? Essa distinção tem a ver com o fato de que os tipos Optional são incorporados na linguagem Swift. Longa história curta sobre eles: tipos opcionais oferecem segurança de memory (isso funciona muito bem com as regras de construtor do Swift – que são rigorosas para fornecer esse benefício).

Uma referência weak permite que a posibilidade dela se torne nil (isso acontece automaticamente quando o object referenciado é desalocado), portanto o tipo de sua propriedade deve ser opcional – assim, você, como programador, é obrigado a verificá-lo antes de usá-lo ( basicamente, o compilador força você, na medida do possível, a escrever código seguro).

Uma referência unowned presume que nunca se tornará nil durante sua vida. Uma referência sem dono deve ser definida durante a boot – isso significa que a referência será definida como um tipo não opcional que pode ser usado com segurança sem verificações. Se, de alguma forma, o object que está sendo referido for desalocado, o aplicativo falhará quando a referência não dita for usada.

Dos documentos da Apple :

Use uma referência fraca sempre que for válido para essa referência se tornar nula em algum momento durante sua vida útil. Por outro lado, use uma referência sem dono quando souber que a referência nunca será nula depois de ter sido definida durante a boot.

Nos documentos, há alguns exemplos que discutem os ciclos de retenção e como quebrá-los. Todos esses exemplos são extraídos dos documentos .

Exemplo para a palavra-chave weak :

 class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? } class Apartment { let number: Int init(number: Int) { self.number = number } weak var tenant: Person? } 

E agora, para alguma arte ASCII (você deve ir ver os documentos – eles têm diagramas bonitos):

 Person ===(strong)==> Apartment Person < ==(weak)===== Apartment 

O exemplo de Person e Apartment mostra uma situação em que duas propriedades, as quais podem ser nulas, têm o potencial de causar um forte ciclo de referência. Esse cenário é melhor resolvido com uma referência fraca. Ambas as entidades podem existir sem ter uma dependência estrita do outro.

Exemplo para a palavra-chave unowned :

 class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } } class CreditCard { let number: UInt64 unowned let customer: Customer init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer } } 

Neste exemplo, um Customer pode ou não ter um cartão de CreditCard , mas um cartão de CreditCard sempre será associado a um Customer . Para representar isso, a class Customer tem uma propriedade de card opcional, mas a class CreditCard tem uma propriedade de customer não opcional (e sem proprietário).

 Customer ===(strong)==> CreditCard Customer < ==(unowned)== CreditCard 

O exemplo de Customer e CreditCard mostra uma situação em que uma propriedade que pode ser nula e outra propriedade que não pode ser nula tem o potencial de causar um forte ciclo de referência. Esse cenário é melhor resolvido com uma referência sem proprietário.

Nota da Apple:

Referências fracas devem ser declaradas como variables, para indicar que seu valor pode mudar em tempo de execução. Uma referência fraca não pode ser declarada como uma constante.

Há também um terceiro cenário quando as duas propriedades sempre devem ter um valor e nenhuma propriedade deve ser nula quando a boot for concluída.

E há também os cenários clássicos do ciclo de retenção a serem evitados ao trabalhar com fechamentos.

Para isso, recomendo que você visite os documentos da Apple ou leia o livro .

Q1 Como é uma referência não familiar diferente de uma referência fraca?

Referência fraca:

Uma referência fraca é uma referência que não mantém uma forte influência na instância a que se refere e, portanto, não impede que a ARC elimine a instância referenciada. Como as referências fracas podem ter “nenhum valor”, você deve declarar todas as referências fracas como tendo um tipo opcional. (Apple Docs)

Referência não conhecida:

Como referências fracas, uma referência sem dono não mantém uma forte influência na instância a que se refere. Ao contrário de uma referência fraca, no entanto, uma referência não proprietária é considerada sempre como um valor. Por causa disso, uma referência não conhecida é sempre definida como um tipo não opcional. (Apple Docs)

Quando usar cada um:

Use uma referência fraca sempre que for válido para essa referência se tornar nula em algum momento durante sua vida útil. Por outro lado, use uma referência sem dono quando souber que a referência nunca será nula depois de ter sido definida durante a boot. (Apple Docs)


Q2 Quando é seguro usar uma “referência sem dono”?

Como citado acima, uma referência sem dono é considerada sempre como um valor. Então você só deve usá-lo quando tiver certeza de que a referência nunca será nula. O Apple Docs ilustra um caso de uso para referências sem proprietário através do exemplo a seguir.

Suponha que tenhamos duas classs Customer e CreditCard . Um cliente pode existir sem um cartão de crédito, mas um cartão de crédito não existirá sem um cliente, ou seja, pode-se supor que um cartão de crédito sempre terá um cliente. Então, eles devem ter o seguinte relacionamento:

 class Customer { var card: CreditCard? } class CreditCard { unowned let customer: Customer } 

Q3 A referência “sem dono” faz referência a um risco de segurança como “pointers pendentes” em C / C ++

Acho que não.

Já que as referências sem dono são apenas referências fracas que têm garantia de ter um valor, não deve ser um risco de segurança de forma alguma. No entanto, se você tentar acessar uma referência sem proprietário após a instância referenciada ser desalocada, você triggersrá um erro de tempo de execução e o aplicativo falhará.

Esse é o único risco que vejo com isso.

Link para o Apple Docs

Se o self puder ser nulo no fechamento, use [self fraco] .

Se o eu nunca será nulo no fechamento, use [self sem dono] .

Se estiver colidindo quando você usa [unown self], então o self provavelmente é nulo em algum momento nesse fechamento e você provavelmente precisará usar [weak self] ao invés disso.

Confira os exemplos sobre o uso de fechamentos fortes , fracos e sem dono :

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html

Extratos do link

Poucos pontos finais

  • Para determinar se você precisa se preocupar com fortes, fracos ou sem dono, pergunte: “Estou lidando com tipos de referência”. Se você está trabalhando com Structs ou Enums, o ARC não está gerenciando a memory para esses tipos e você nem precisa se preocupar em especificar fraca ou sem dono para essas constantes ou variables.
  • Referências fortes são boas em relacionamentos hierárquicos onde o pai faz referência ao filho, mas não vice-versa. Na verdade, referências fortes são o tipo de referência mais apropriado na maioria das vezes.
  • Quando duas instâncias são opcionalmente relacionadas umas às outras, certifique-se de que uma dessas instâncias contenha uma referência fraca à outra.
  • Quando duas instâncias são relacionadas de tal forma que uma das instâncias não pode existir sem a outra, a instância com a dependência obrigatória precisa manter uma referência não pertencente à outra instância.

Do livro de Jon Hoffman, “Mastering Swift 4”:

A diferença entre uma referência fraca e uma referência sem dono é que a instância à qual uma referência fraca se refere pode ser nula, enquanto a instância à qual uma referência não pertencente se refere não pode ser nula. Isso significa que, quando usamos uma referência fraca, a propriedade deve ser uma propriedade opcional, pois pode ser nula.

Referências sem referência são um tipo de referência fraca usada no caso de um relacionamento de vida igual entre dois objects, quando um object deve pertencer a um outro object. É uma maneira de criar uma binding imutável entre um object e uma de suas propriedades.

No exemplo dado no vídeo WWDC rápido intermediário, uma pessoa possui um cartão de crédito, e um cartão de crédito pode ter apenas um titular. No cartão de crédito, a pessoa não deve ser uma propriedade opcional, porque você não quer ter um cartão de crédito flutuando com apenas um proprietário. Você pode quebrar esse ciclo tornando a propriedade do titular no crédito uma referência fraca, mas isso também exige que você a torne opcional e variável (em vez de constante). A referência sem dono neste caso significa que, embora o CreditCard não tenha uma participação em uma Pessoa, sua vida depende disso.

 class Person { var card: CreditCard? } class CreditCard { unowned let holder: Person init (holder: Person) { self.holder = holder } }