weak y unowned no poseen su destino, pero difieren tras liberarlo. weak pasa a nil; acceder a un destino liberado mediante unowned seguro causa un error en ejecución. Decide según garantías de vida, no solo por la sintaxis opcional.
Mecanismo y decisión de diseño
ARC combina operaciones de propiedad generadas por el compilador con gestión de referencias en ejecución. Un ciclo fuerte puede sobrevivir a sus propietarios externos. unowned admite opcionales, pero debes mantener una referencia válida o asignarle nil explícitamente. Fuente primaria
Código reproducible
Primero dos Node se poseen mutuamente; eliminamos referencias fuertes externas, observamos su supervivencia con weak y rompemos una conexión. Después usamos una relación fuerte de padre a hijo y débil en sentido inverso. Finalmente limpiamos un unowned opcional mientras Owner sigue vivo.
Este ejemplo independiente se ejecutó el 2026-10-23 con Apple Swift 6.4 para arm64 macOS, en modo de lenguaje Swift 6. No necesita red ni paquetes adicionales.
Descargar el archivo Swift completo
Ejecuta el comando en la carpeta de descarga. Las precondiciones detienen la ejecución si falla una comprobación. No uses -Ounchecked: elimina estas comprobaciones.
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")
Salida registrada e interpretación
cycle=retained broken=released weak=nil unowned-optional=manually-cleared
El ciclo fuerte sobrevive al bloque, pero ambas observaciones pasan a nil al romper una conexión. La relación padre-hijo con retorno weak se libera al desaparecer los propietarios fuertes. El unowned opcional es nil por asignación explícita, no por borrado automático.
Alcance y limitaciones
El programa no accede a un unowned inválido ni afirma haber medido ese fallo. No generalices una liberación a una línea exacta: influyen optimización y extensión de vida. La ausencia de un registro de deinit no prueba una fuga; una caché o tarea asíncrona puede retener legítimamente.
Qué comprobar después
Dibuja el grafo de propiedad y decide si la relación inversa debe poseer el destino. Usa weak si su desaparición es válida y considera unowned solo con garantía de vida durante el acceso. Continúa con capturas si una clausura almacenada retiene a su propietario.
Fuentes y verificación
- The Swift Programming Language: Automatic Reference CountingSwift.org · Documentación oficial · Consultado 23 de octubre de 2026Respalda: Fuente del contrato de implementación y de la explicación. La salida se comprobó por separado con el experimento incluido aquí.

