Na sessão 403 da WWDC 2014, Swift intermediário e transcrição , houve o seguinte slide
O orador disse que, nesse caso, se não usarmos [unowned self]
lá, será um vazamento de memória. Isso significa que devemos sempre usar o [unowned self]
fechamento interno?
Na linha 64 do ViewController.swift do aplicativo Swift Weather , eu não uso [unowned self]
. Mas eu atualizo a interface do usuário usando alguns @IBOutlet
s como self.temperature
e self.loadingIndicator
. Pode ser bom, porque todos os que @IBOutlet
eu defini são weak
. Mas por segurança, devemos sempre usar [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
swift
automatic-ref-counting
Jake Lin
fonte
fonte
onChange
deve ser um[weak self]
fechamento, já que é uma propriedade pública (internamente, mas ainda), para que outro objeto possa obter e armazenar o fechamento, mantendo o objeto TempNotifier por perto (indefinidamente se o objeto using não soltou oonChange
fechamento até ver oTempNotifier
desaparecimento, através de sua própria referência fraca para oTempNotifier
) . Sevar onChange …
fosseprivate var onChange …
então[unowned self]
estaria correto. Não tenho 100% de certeza disso; alguém me corrija por favor se eu estiver errado.[]
? Não consigo encontrar a explicação nos documentos da Apple.{}
é o fechamento vazio (a instância do fechamento) como o padrão (não faz nada),(Int) -> Void
é a definição de fechamento.Respostas:
Não, definitivamente existem momentos em que você não gostaria de usar
[unowned self]
. Às vezes, você deseja que o fechamento se capture para garantir que ele ainda esteja disponível quando o fechamento for chamado.Exemplo: Fazendo uma Solicitação de Rede Assíncrona
Se você estiver fazendo uma solicitação de rede assíncrona , deseja que o fechamento seja retido
self
quando a solicitação terminar. Caso contrário, esse objeto pode ter sido desalocado, mas você ainda poderá lidar com o acabamento da solicitação.Quando usar
unowned self
ouweak self
O único momento em que você realmente deseja usar
[unowned self]
ou[weak self]
é quando criaria um forte ciclo de referência . Um forte ciclo de referência é quando existe um ciclo de propriedade em que os objetos acabam se possuindo (talvez através de terceiros) e, portanto, nunca serão desalocados, pois ambos garantem que os outros fiquem por perto.No caso específico de um fechamento, você só precisa perceber que qualquer variável referenciada dentro dele é "propriedade" do fechamento. Enquanto o fechamento estiver próximo, é garantido que esses objetos estejam ao redor. A única maneira de interromper essa propriedade é fazer o
[unowned self]
ou[weak self]
. Portanto, se uma classe possui um fechamento, e esse fechamento captura uma forte referência a essa classe, você tem um forte ciclo de referência entre o fechamento e a classe. Isso também inclui se a classe possui algo que possui o fechamento.Especificamente no exemplo do vídeo
No exemplo no slide,
TempNotifier
possui o fechamento através daonChange
variável de membro. Se eles não declarassemself
comounowned
, o fechamento também seria responsável porself
criar um forte ciclo de referência.Diferença entre
unowned
eweak
A diferença entre
unowned
eweak
é queweak
é declarada como opcional enquantounowned
não é. Ao declarar,weak
você pode lidar com o caso de que ele pode estar nulo dentro do fechamento em algum momento. Se você tentar acessar umaunowned
variável que é nula, ela travará o programa inteiro. Portanto, use somenteunowned
quando tiver certeza de que a variável sempre estará presente enquanto o fechamento estiver próximofonte
[weak self]
em uma solicitação de rede assíncrona, está em um controlador de exibição em que essa solicitação é usada para preencher a exibição. Se o usuário voltar, não precisamos mais preencher a visualização, nem precisaremos de uma referência ao controlador de visualização.weak
as referências também são definidas paranil
quando o objeto é desalocado.unowned
referências não são.unowned
é usado pornon-Optional
enquantoweak
é usado paraOptional
então nossoself
éOptional
ounon-optional
?Atualização 11/2016
Eu escrevi um artigo sobre isso estendendo esta resposta (procurando no SIL para entender o que o ARC faz), confira aqui .
Resposta original
As respostas anteriores não fornecem regras diretas sobre quando usar uma sobre a outra e por que, então, deixe-me acrescentar algumas coisas.
A discussão sem dono ou fraca se resume a uma questão de vida útil da variável e do fechamento que a referencia.
Cenários
Você pode ter dois cenários possíveis:
O fechamento tem o mesmo tempo de vida útil da variável, portanto, o fechamento será alcançável apenas até que a variável seja alcançável . A variável e o fechamento têm a mesma vida útil. Nesse caso, você deve declarar a referência como sem dono . Um exemplo comum é o
[unowned self]
usado em muitos exemplos de pequenos fechamentos que fazem algo no contexto de seus pais e que não sendo referenciados em nenhum outro lugar não sobrevivem aos pais.O tempo de vida do fechamento é independente do da variável, o fechamento ainda pode ser referenciado quando a variável não estiver mais acessível. Nesse caso, você deve declarar a referência como fraca e verificar se não é nula antes de usá-la (não force a desembrulhar). Um exemplo comum disso é o que
[weak delegate]
você pode ver em alguns exemplos de fechamento que referenciam um objeto delegado completamente não relacionado (vitalício).Uso real
Então, qual / você realmente deve usar na maioria das vezes?
Citando Joe Groff do twitter :
Você encontrará mais sobre
*
o funcionamento interno não proprietário aqui .*
Geralmente também chamado de não proprietário (seguro) para indicar que as verificações em tempo de execução (que levam a falhas de referências inválidas) são executadas antes de acessar a referência não proprietária.fonte
Eu pensei em adicionar alguns exemplos concretos especificamente para um controlador de exibição. Muitas das explicações, não apenas aqui no Stack Overflow, são realmente boas, mas eu trabalho melhor com exemplos do mundo real (@drewag teve um bom começo nisso):
weak
, use , porque eles têm vida longa. O controlador de exibição pode fechar antes que a solicitação seja concluída, para queself
não aponte mais para um objeto válido quando o fechamento for chamado.Se você tiver um fechamento que lide com um evento em um botão. Isso
unowned
ocorre porque, assim que o controlador de exibição desaparece, o botão e quaisquer outros itens dos quais ele pode estar se referindoself
desaparecem ao mesmo tempo. O bloco de fechamento também desaparecerá ao mesmo tempo.fonte
weak
e nãounowned
certo?Se o eu puder ser nulo no fechamento, use [eu fraco] .
Se o eu nunca for nulo no fechamento, use [eu sem dono] .
A documentação do Apple Swift possui uma ótima seção com imagens explicando a diferença entre o uso de fechamentos fortes , fracos e não proprietários em fechamentos:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
fonte
Aqui estão citações brilhantes dos Fóruns de desenvolvedores da Apple que descrevem deliciosos detalhes:
unowned
vsunowned(safe)
vsunowned(unsafe)
unowned
vsweak
Atualização: no Swift moderno,
weak
internamente, usa o mesmo mecanismo que ounowned
faz . Portanto, essa comparação está incorreta porque compara Objective-Cweak
com Swiftunonwed
.Razões
Animado, hein?
fonte
Há ótimas respostas aqui. Porém, mudanças recentes na maneira como o Swift implementa referências fracas devem mudar o eu fraco de todos em relação às decisões de uso de si próprias. Anteriormente, se você precisasse do melhor desempenho usando o eu sem dono era superior ao eu fraco, desde que você pudesse ter certeza de que o eu nunca seria nulo, porque acessar o eu sem dono é muito mais rápido do que acessar o eu fraco.
Mas Mike Ash documentou como o Swift atualizou a implementação de vars fracos para usar mesas laterais e como isso melhora substancialmente o fraco desempenho de auto.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
Agora que não há uma penalidade de desempenho significativa para o eu fraco, acredito que deveríamos usar isso daqui para frente. O benefício do self fraco é que ele é opcional, o que torna muito mais fácil escrever um código mais correto; é basicamente o motivo pelo qual o Swift é uma linguagem tão boa. Você pode pensar que sabe quais situações são seguras para o uso de si mesmo, mas minha experiência na revisão de muitos outros códigos de desenvolvedores é que a maioria não sabe. Corrigi muitas falhas em que o self sem dono foi desalocado, geralmente em situações em que um thread em segundo plano é concluído depois que um controlador é desalocado.
Erros e falhas são as partes da programação que consomem mais tempo, são mais dolorosas e caras. Faça o seu melhor para escrever o código correto e evite-o. Eu recomendo que seja uma regra nunca forçar desembrulhar os opcionais e nunca usar o eu sem dono em vez do eu fraco. Você não perderá nada perdendo as vezes que forçam o desembrulhamento e o eu sem dono na verdade é seguro. Mas você ganhará muito ao eliminar e encontrar falhas e erros difíceis de encontrar.
fonte
weak
que não pode ser usado no lugar de umunowned
?De acordo com a Apple-doc
Exemplo -
fonte
Se nenhuma das opções acima fizer sentido:
tl; dr
Explicação:
Eu recuperei o seguinte abaixo em: link não proprietário fraco . Pelo que deduzi, o eu sem dono não pode ser nulo, mas o eu fraco pode ser, e o eu sem dono pode levar a indicadores pendentes ... algo infame no Objective-C. Espero que ajude
Referências não proprietárias, como referências fracas, não aumentam a contagem de retenção do objeto que está sendo referido. No entanto, no Swift, uma referência não proprietária tem o benefício adicional de não ser um opcional . Isso os torna mais fáceis de gerenciar, em vez de recorrer ao uso de ligação opcional. Isso não é diferente dos Opcionais Implicitamente Desembrulhados. Além disso, as referências não proprietárias não são zeradas . Isso significa que, quando o objeto é desalocado, ele não zera o ponteiro. Isso significa que o uso de referências não proprietárias pode, em alguns casos, levar a indicadores pendentes. Para vocês nerds que se lembram dos dias de Objective-C como eu, as referências não proprietárias são mapeadas para referências não seguras e sem retenção.
É aqui que fica um pouco confuso.
Ambos podem ser usados para interromper os ciclos de retenção. Então, quando os usamos ?!
De acordo com os documentos da Apple :
fonte
fonte