Weak Reference (referência fraca) é uma referência a um objeto que não aumenta seu contador de retenção no ARC. De acordo com Apple Swift Language Guide, 2026, referências fracas são declaradas com a palavra-chave weak e são sempre opcionais. Quando o objeto é liberado, todas as referências fracas a ele são automaticamente definidas como nil, prevenindo ponteiros pendentes e tornando as referências fracas um mecanismo seguro para quebrar ciclos de retenção.
Principais pontos
weak antes de var; tipo sempre opcional (?)Weak Reference é uma referência não proprietária a um objeto no ARC (Automatic Reference Counting). Ao contrário de uma referência forte, que aumenta o retain count do objeto e garante seu tempo de vida, uma referência fraca permite que o objeto seja liberado mesmo se ainda estiver sendo referenciado. Após a desalocação, a referência fraca é automaticamente definida como nil — isso é chamado de zeroing weak.
Zeroing weak é uma característica chave do runtime de Swift e Objective-C. Quando o contador de referências de um objeto atinge zero e o objeto é desalocado, o runtime percorre todas as referências fracas para este objeto (armazenadas em uma tabela fraca especial) e as define como nil. Isso garante que o acesso à memória liberada (use-after-free) seja impossível através de referências fracas — qualquer leitura retorna nil.
De acordo com a Apple WWDC 2012 Session 406, as referências fracas zeroing eliminaram toda uma classe de bugs de crash relacionados a ponteiros pendentes (dangling pointers), que eram comuns no gerenciamento manual de memória (MRR). No MRR, referências fracas existiam apenas como __unsafe_unretained — elas não zeravam, e acessar um objeto desalocado resultava em EXC_BAD_ACCESS.
Vejamos a sintaxe para declarar referências fracas em ambas as linguagens do ecossistema Apple. Apesar do runtime compartilhado, a sintaxe difere, mas a semântica é idêntica.
Em Swift, referências fracas são declaradas com a palavra-chave weak antes de var. O tipo deve ser sempre opcional (Type?), pois a referência pode se tornar nil a qualquer momento. Constantes (let) não podem ser weak — apenas variáveis.
class ViewController: UIViewController {
// weak properties: only var, only optional
weak var delegate: ViewControllerDelegate?
weak var parentView: UIView?
weak var completionHandler: ((Bool) -> Void)? // ⚠️ closures não armazenam weak
// ⬆️ Erro: weak só pode ser aplicado a tipos class, não a closures
}
Importante: weak é aplicável apenas a instâncias de classe (tipos class), AnyObject e protocolos herdados de AnyObject. Struct, enum e closures não podem ser weak — são tipos valor e não participam do ARC.
Em Objective-C, propriedades fracas são declaradas usando o atributo __weak ou o modificador weak em declarações de propriedade:
// Objective-C: weak property
@interface MyViewController : UIViewController
@property (weak, nonatomic) id<MyDelegate> delegate;
@end
// Variável local fraca
__weak MyObject *weakRef = someStrongObject;
O runtime do Objective-C também fornece zeroing weak, mas adicionalmente bloqueia o uso de weak com estruturas C e alguns objetos Core Foundation. Para estes, usa-se __unsafe_unretained — sem zeroing.
Referências fracas não são uma solução universal, mas uma ferramenta para cenários específicos. Usar weak em toda parte leva a complexidade desnecessária e prejudica a legibilidade. Vejamos os cenários de uso corretos.
Delegados — o cenário principal para weak. O objeto proprietário (por exemplo, UITableView) mantém uma referência forte a si mesmo, enquanto o delegado (UIViewController) não deve possuir a tabela. O Apple SDK garante que todos os delegates e dataSources são weak. Para seus próprios protocolos, use sempre weak var delegate.
Quando um objeto filho precisa referenciar seu pai (por exemplo, ChildViewController acessando um coordenador), use uma referência fraca. O pai possui o filho (strong), o filho observa o pai (weak) — o ciclo de retenção é eliminado.
Capture list [weak self] — a maneira padrão de evitar ciclos de retenção em closures armazenadas como propriedades de classe. Se self pode ser desalocado antes da conclusão da closure, weak self é obrigatório.
| Cenário | Weak | Strong |
|---|---|---|
| Delegate | ✅ Sempre weak | ❌ Retain cycle |
| Pai → Filho | ❌ Não necessário (pai deve possuir) | ✅ Strong |
| Filho → Pai | ✅ Weak | ❌ Retain cycle |
| Callback assíncrono | ✅ [weak self] | ❌ Risco de retain cycle |
| Acoplamento forte (owned) | ❌ unowned | ✅ Strong |
Regra geral: se o objeto A possui B (A → B strong), então B → A deve ser weak ou unowned. A direção das referências fortes deve ser sempre do proprietário ao subordinado.
Tanto weak quanto unowned não aumentam o retain count, mas diferem no comportamento após a desalocação do objeto. A escolha entre eles é uma questão de garantias de tempo de vida.
Weak: torna-se nil automaticamente, tipo sempre opcional, requer unwrap antes do uso. Seguro — acessar nil não causa crash.
Unowned: não se torna nil, tipo não opcional. Se o objeto for desalocado, uma referência unowned se torna um ponteiro pendente — acessá-la causa um crash em tempo de execução. Unowned assume que o objeto vive pelo menos tanto quanto o lado que o referencia.
Escolha weak se: o objeto pode ser desalocado a qualquer momento (delegado após fechar a tela), você não controla o tempo de vida do objeto, ou está inseguro sobre as garantias. Weak é a escolha segura universal.
Escolha unowned se: o objeto tem garantia de não ser desalocado antes do objeto que o referencia (por exemplo, Cliente → CartaoCredito, onde o cartão não existe sem o cliente). Unowned fornece uma API não opcional sem unwrap, o que é mais conveniente no código.
class Order {
let id: Int
var items: [Item] = []
init(id: Int) { self.id = id }
// Relação forte: Order possui Item
func addItem(name: String) {
let item = Item(name: name, order: self)
items.append(item)
}
}
class Item {
let name: String
unowned let order: Order // ✅ unowned — Item não vive sem Order
init(name: String, order: Order) {
self.name = name
self.order = order
}
}
// Exemplo com weak: delegate sem garantia de tempo de vida
protocol NetworkServiceDelegate: AnyObject {
func didReceiveResponse(data: Data)
}
class NetworkService {
weak var delegate: NetworkServiceDelegate? // ✅ weak — o delegate pode desaparecer
}
No exemplo, Item usa unowned porque um item de pedido não pode existir sem o próprio pedido — a garantia de tempo de vida é inabalável. NetworkService usa weak porque o delegado (por exemplo, ViewController) pode ser fechado e desalocado a qualquer momento.
Referências fracas são uma ferramenta poderosa, mas têm limitações que são importantes de entender para o uso correto no desenvolvimento iOS.
Referências fracas são mais lentas que as fortes: a cada acesso, o runtime verifica se o objeto foi desalocado (lookup na tabela fraca). Na grande maioria dos cenários, a diferença é imperceptível, mas em loops críticos com milhões de acessos, weak pode se tornar um gargalo. Para cenários de alta carga, use strong e reorganize a arquitetura.
Struct, enum, tuple — tipos valor que não participam do ARC. Tentar declarar um weak struct resulta em erro de compilação. Para armazenar uma referência fraca a um tipo valor, use um wrapper em um tipo classe ou uma closure.
Zeroing weak é thread-safe: se um objeto for desalocado em uma thread, a referência fraca é zerada em todas as threads atomicamente. No entanto, a janela entre ler uma referência fraca e desreferenciá-la pode levar a uma condição de corrida — o objeto é desalocado entre a obtenção da referência fraca e seu uso. Solução: captura forte da referência fraca em uma variável local.
// Race condition com weak em multithreading
func performAsync() {
weak var weakSelf = self
queue.async {
// ⚠️ weakSelf pode ser nil entre a verificação e o uso
if weakSelf != nil {
weakSelf!.doSomething() // CRASH se ficar nil
}
}
}
// ✅ Correção: captura forte durante o uso
func performAsyncSafe() {
queue.async { [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething() // strongSelf — referência local forte
}
}
Na versão segura, weak self é capturado e imediatamente desembrulhado em uma variável local forte strongSelf. Se self ainda estiver vivo, permanecerá vivo durante a execução do bloco. Se não, guard é acionado e o código não é executado. Este idiom é o padrão para closures assíncronas em Swift.
IBOutlet no Interface Builder deve ser weak porque a hierarquia de views já mantém uma referência forte à subview. Duplicar uma referência forte no controlador não cria um ciclo de retenção, mas é redundante. Uma referência fraca a um outlet é a recomendação da Apple, embora muitos desenvolvedores usem strong para simplificar o código.
Perguntas frequentes
Não, weak só pode apontar para um objeto existente ou nil. Ao criar um novo objeto, você primeiro obtém uma referência forte (através de um inicializador), e só então pode atribuir uma referência fraca. Um weak nil no início é um estado normal.
Weak é baseado no ARC, que gerencia apenas tipos referência (classes). Tipos valor (struct, enum) são copiados na atribuição e não têm retain count. Para relacionamentos fracos com tipos valor, use closures ou wrappers em uma classe com uma propriedade weak.
Cada acesso a uma referência fraca realiza um lookup na tabela do runtime. Em um loop com milhões de iterações, isso pode ser de 2 a 5 vezes mais lento que uma referência forte. Para caminhos críticos, copie weak para uma variável local forte antes do loop.
Quando todas as referências fortes ao objeto são perdidas — no final do escopo, ao reatribuir uma propriedade, ou ao fechar uma tela. Em um ambiente multithread, isso pode acontecer entre duas linhas de código. Sempre verifique referências fracas com guard let ou if let.
Semanticamente idênticos: ambos fornecem zeroing weak. Diferenças: Swift requer tipo opcional e var, Objective-C usa um modificador de propriedade. Objective-C também suporta __unsafe_unretained — uma referência fraca sem zeroing (risco de ponteiro pendente).
Resumo
weak var + tipo opcional; apenas tipos class e protocolos AnyObjectVamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também