weak e unowned não possuem seus alvos, mas diferem após a liberação. weak vira nil; acessar um alvo liberado por unowned seguro causa erro em execução. Escolha conforme a garantia de vida, não apenas pela sintaxe opcional.
Mecanismo e decisão de projeto
ARC combina operações de propriedade geradas pelo compilador com gerenciamento de referências em execução. Um ciclo forte pode sobreviver aos proprietários externos. unowned admite opcionais, mas cabe ao programador manter um alvo válido ou atribuir nil explicitamente. Fonte primária
Código reproduzível
Primeiro dois Node possuem um ao outro; removemos referências fortes externas, observamos sua sobrevivência com weak e rompemos uma ligação. Depois usamos uma ligação forte do pai ao filho e weak no sentido inverso. Por fim, limpamos um unowned opcional enquanto Owner permanece vivo.
Este exemplo independente foi executado em 2026-10-23 com Apple Swift 6.4 para arm64 macOS, no modo de linguagem Swift 6. Não requer rede nem pacotes adicionais.
Baixar o arquivo Swift completo
Execute o comando na pasta do download. As precondições interrompem a execução se uma verificação falhar. Não use -Ounchecked: essa opção remove as verificações.
swift -swift-version 6 swift-arc-weak-unowned.swift
final class Node { var next: Node? }
func breakCycle(_ node: Node) { node.next = nil }
weak var observedA: Node?
weak var observedB: Node?
do {
let a = Node()
let b = Node()
a.next = b
b.next = a
observedA = a
observedB = b
}
precondition(observedA != nil && observedB != nil)
breakCycle(observedA!)
precondition(observedA == nil && observedB == nil)
final class Owner { var child: Child? }
final class Child { weak var owner: Owner? }
weak var observedOwner: Owner?
weak var observedChild: Child?
do {
let owner = Owner()
let child = Child()
owner.child = child
child.owner = owner
observedOwner = owner
observedChild = child
}
precondition(observedOwner == nil && observedChild == nil)
final class Borrower {
unowned var owner: Owner?
init(_ owner: Owner) { self.owner = owner }
}
do {
let owner = Owner()
let borrower = Borrower(owner)
withExtendedLifetime(owner) {
precondition(borrower.owner === owner)
borrower.owner = nil
precondition(borrower.owner == nil)
}
}
print("cycle=retained broken=released weak=nil unowned-optional=manually-cleared")
Saída registrada e interpretação
cycle=retained broken=released weak=nil unowned-optional=manually-cleared
O ciclo forte sobrevive ao bloco, mas ambas as observações viram nil após romper uma ligação. A relação pai-filho com retorno weak é liberada quando os proprietários fortes desaparecem. O unowned opcional fica nil por atribuição explícita, não por limpeza automática.
Escopo e limitações
O programa não acessa um unowned inválido nem afirma ter medido essa falha. Não generalize a liberação para uma linha exata: otimização e extensão de vida influenciam. A ausência de um log de deinit não prova vazamento; caches ou tarefas assíncronas podem reter objetos legitimamente.
O que verificar em seguida
Desenhe o grafo de propriedade e decida se a ligação inversa deve possuir o alvo. Use weak quando o desaparecimento for válido e considere unowned apenas com garantia de vida durante o acesso. Continue com capturas se uma closure armazenada retém seu proprietário.
Fontes e verificação
- The Swift Programming Language: Automatic Reference CountingSwift.org · Documentação oficial · Consultado 23 de outubro de 2026Evidência: Fonte do contrato de implementação e da explicação. A saída foi verificada separadamente com o experimento incluído aqui.

