Strong Reference (referência forte): o que é, mecanismo de funcionamento e ARC

Autor: IT Sectr Publicado: 2026-03-30 Tempo de leitura: 9 min

Strong Reference (referência forte) é um mecanismo padrão de gerenciamento de memória no qual um objeto permanece na memória enquanto pelo menos uma referência ativa apontar para ele. Ao contrário das referências fracas, uma referência forte incrementa o contador de referências do objeto e impede sua liberação automática. De acordo com a Apple Developer Documentation, o ARC gerencia automaticamente o ciclo de vida dos objetos em Swift e Objective-C. Compreender o funcionamento das referências fortes é fundamental para prevenir vazamentos de memória e dependências cíclicas em aplicações móveis.

Pontos principais

  • Strong Reference — uma referência que mantém um objeto na memória incrementando seu retain count em 1.
  • ARC insere automaticamente operações retain e release, eliminando o gerenciamento manual de memória em Swift e Objective-C.
  • Retain cycle ocorre quando dois objetos se referenciam mutuamente por meio de referências fortes — a memória nunca é liberada.
  • Weak Reference não incrementa o contador de referências e se torna nil automaticamente quando o objeto é desalocado.
  • Unowned Reference não incrementa o contador, mas assume que o objeto não vive mais que seu proprietário.

O que é Strong Reference?

Strong Reference é um tipo de referência a um objeto que impede sua destruição pelo coletor de lixo ou sistema de gerenciamento de memória. Enquanto existir pelo menos uma referência forte ao objeto, sua memória não é liberada. Este é o mecanismo básico no qual se baseiam o ARC em Swift e Objective-C e a coleta de lixo em Java e Kotlin.

O conceito de referência forte é fundamental para todas as linguagens com gerenciamento automático de memória. Em sistemas com ARC, cada referência forte incrementa o contador de referências do objeto. Quando o contador chega a zero, o objeto é imediatamente desalocado. Em Java e Kotlin com coleta de lixo, uma referência forte garante que o objeto é alcançável e não será coletado pelo GC.

De acordo com a WWDC 2021, cerca de 35% dos vazamentos de memória em aplicações iOS estão relacionados ao uso incorreto de referências fortes e ciclos de retenção. No desenvolvimento Android, vazamentos por meio de referências fortes implícitas em closures e callbacks são a segunda causa mais frequente de problemas de memória depois do Context Leak.

Para trabalhar eficazmente com a memória, é necessário entender a diferença entre referências strong, weak e unowned, e escolher o tipo de referência adequado com base na propriedade e no ciclo de vida dos objetos.

Como o ARC mudou o gerenciamento de memória

Antes do ARC, os desenvolvedores chamavam manualmente retain e release para cada objeto, o que causava inúmeros erros. O ARC, apresentado pela Apple em 2011 com o LLVM 3.0, automatizou esse processo analisando o grafo de propriedade em tempo de compilação. O próprio compilador insere chamadas retain, release e autorelease onde necessário.

De acordo com o Clang Static Analyzer, a introdução do ARC reduziu os bugs relacionados à memória em aplicações iOS em 70%. Para os desenvolvedores, isso significa que o gerenciamento de memória se tornou mais seguro, mas ao mesmo tempo surgiu a necessidade de entender como as referências fortes funcionam internamente — para evitar retain cycles.

Em Kotlin e Java, o coletor de lixo desempenha o papel do ARC, mas o princípio da referência forte permanece o mesmo: GC Roots são os pontos de entrada pelos quais os objetos são mantidos por referências fortes. Enquanto um objeto for alcançável por uma cadeia de referências fortes a partir de uma GC Root, ele não será coletado.

Como o Strong Reference funciona no ARC?

ARC (Automatic Reference Counting) funciona contando as referências de cada objeto no heap. Quando uma nova referência forte a um objeto é criada, o contador aumenta (retain). Quando a referência é destruída ou sobrescrita, o contador diminui (release). Quando o contador chega a zero, o objeto é imediatamente removido da memória.

Considere um exemplo em Swift. Ao criar uma instância de uma classe, o ARC aloca memória e define o retain count como 1. Cada nova atribuição a outra variável incrementa o contador. Quando a variável sai do escopo, o contador diminui:

swift
class ProfileViewController {
    var nameLabel: String?
    var avatarImage: UIImage?

    func loadProfile() {
        // retain count = 1 para nova instância
        let user = User(name: "Ivan")
        // retain count = 2 após atribuir nameLabel
        nameLabel = user.name
        // saída do método — user sai do escopo, retain count = 1
    }
}

Neste código, o ARC garante que o objeto User permaneça na memória enquanto houver pelo menos uma referência forte apontando para ele. Quando a função loadProfile termina, a variável local user é destruída, mas nameLabel ainda mantém o objeto. A memória só será liberada quando nameLabel deixar de existir ou for sobrescrita.

Em Kotlin, um comportamento semelhante é fornecido por meio de GC Roots. Enquanto existir uma cadeia rastreável de referências fortes a partir de uma raiz do coletor de lixo (por exemplo, um campo estático ou uma thread ativa), o objeto permanece na memória. A diferença é que o GC não libera memória instantaneamente — isso ocorre de forma assíncrona após a análise de alcançabilidade.

Quando ocorre a liberação de memória

No ARC, a liberação ocorre de forma síncrona quando o contador chega a zero. Em Swift e Objective-C, você sabe exatamente quando o objeto será removido. Em Kotlin e Java, o momento da liberação é imprevisível, mas isso é compensado por um esquema mais flexível para detectar dependências cíclicas no nível do coletor de lixo.

Retain Cycles e vazamentos de memória

Retain cycle (ciclo de retenção) é uma situação em que dois ou mais objetos têm referências fortes mútuas entre si. Como resultado, seu retain count nunca chega a zero e a memória nunca é liberada, mesmo depois que os objetos não são mais necessários para a aplicação.

Um exemplo clássico: um view controller pai mantém um objeto filho com uma referência forte, e este por sua vez mantém o pai com uma referência forte. Isso é típico em situações com delegados, closures e expressões lambda aninhadas. De acordo com o Instruments Leaks, os retain cycles representam até 60% de todos os vazamentos de memória em aplicações que usam ARC.

swift
class ParentViewController: UIViewController {
    var child: ChildViewController?

    func setupChild() {
        child = ChildViewController()
        // retain cycle: pai mantém filho, filho mantém pai via closure
        child?.onEvent = {
            self.handleEvent()
        }
    }

    func handleEvent() {}
}

O problema aqui é que a closure onEvent captura self (ParentViewController) com uma referência forte, e o ParentViewController mantém child com uma referência forte. Ambos os objetos nunca serão liberados. A solução é usar weak self na closure para quebrar o ciclo.

Em Kotlin, ciclos semelhantes surgem quando lambdas capturam objetos externos. O coletor de lixo da JVM pode detectar esses ciclos com o tempo, mas apenas se os objetos forem inalcançáveis a partir de GC Roots. Se o ciclo estiver vinculado a uma thread ativa ou contexto de UI, o vazamento persiste por toda a vida da aplicação.

Strong vs Weak vs Unowned Reference

Entender a diferença entre os tipos de referência é fundamental para o gerenciamento seguro de memória. Strong Reference incrementa o retain count. Weak Reference não incrementa o retain count e se torna nil automaticamente quando o objeto é desalocado. Unowned Reference também não incrementa o retain count, mas não é zerada — acessá-la após a desalocação causa um crash.

Tipo de referênciaRetain countSegurançaQuando usar
Strong+1Segura (padrão)Propriedade do objeto, relação pai → filho
WeakNão alteraAnulação automática (segura)Delegados, callbacks, referências inversas
UnownedNão alteraRisco de crash ao acessar tardiamenteQuando o objeto vive garantidamente mais que o proprietário

A escolha do tipo de referência é ditada pela relação de propriedade. Se o objeto B faz parte de A e não pode existir sem ele — use Strong. Se B pode existir independentemente e referencia A para notificações — use Weak. Unowned é raramente usado — apenas quando a vida do objeto filho estritamente não excede a vida do pai.

Regra prática de seleção

Apple Developer Documentation recomenda: por padrão, use strong para todas as relações de propriedade. Se precisar evitar um retain cycle — determine qual referência deve ser fraca. Geralmente é a referência inversa na hierarquia (filho → pai). Em Kotlin, um papel semelhante é desempenhado por WeakReference de java.lang.ref, usado para caches e padrões observer.

Como corrigir problemas com referências fortes

Detectar retain cycles é o primeiro passo. O segundo é eliminá-los corretamente. A ferramenta principal para quebrar ciclos de referências fortes é substituir uma das referências por weak ou unowned. Em linguagens com coleta de lixo, WeakReference com verificação manual de null antes de cada acesso é adicionalmente usado.

Em Swift e Objective-C, a correção mais comum é adicionar [weak self] nas closures. Isso garante que a closure não retenha o objeto após sua desalocação. Em Kotlin, wrappers WeakReference ou limpeza explícita de referências em onDestroy são usados para fins semelhantes.

swift
class NetworkService {
    func fetchData(completion: @escaping (Data?) -> Void) {
        // captura com weak self — retain cycle eliminado
        URLSession.shared.dataTask(
            with: URL(string: "https://api.example.com")!
        ) { [weak self] data, response, error in
            guard let self else { return }
            completion(data)
        }.resume()
    }
}

Neste exemplo, [weak self] garante que NetworkService não seja retido pela closure depois que não for mais necessário. Se self for desalocado antes da requisição ser concluída — guard let self else { return } sai da closure sem chamar completion.

Para diagnóstico de retain cycles, use Instruments Leaks para iOS ou Android Profiler + LeakCanary para Android. Essas ferramentas mostram o grafo exato de retenção e indicam qual referência forte está impedindo a desalocação do objeto. A criação regular de perfis de memória deve fazer parte do pipeline CI/CD de qualquer projeto móvel.

Strong Reference em Swift e Kotlin — comparação

Swift e Kotlin usam mecanismos de gerenciamento de memória fundamentalmente diferentes, mas o conceito de referência forte existe em ambos. Swift usa ARC com liberação síncrona ao atingir retain count = 0. Kotlin usa um GC de rastreamento que limpa assincronamente objetos inalcançáveis.

ParâmetroSwift (ARC)Kotlin (JVM GC)
MecanismoContagem de referências (retain count)Rastreamento de alcançabilidade (GC Roots)
LiberaçãoSíncrona (quando o contador chega a zero)Assíncrona (por ciclo do GC)
Retain cycleNão detectado automaticamenteGC pode detectar, mas não imediatamente
Weak refweak (anulação automática)WeakReference (verificação manual)

A principal diferença prática: em Swift, um retain cycle é um vazamento garantido. Em Kotlin, o GC pode quebrar o ciclo se os objetos forem inalcançáveis da raiz, mas o tempo de vida dos objetos vazados permanece imprevisível. Portanto, em ambas as linguagens, a melhor estratégia é evitar ciclos de referências fortes na fase de projeto.

Para Swift, use weak em padrões de delegado e closures. Para Kotlin, use WeakReference ou componentes Lifecycle-aware que limpam automaticamente as referências quando o proprietário é destruído. Em ambas as abordagens, o objetivo é o mesmo — eliminar referências fortes onde elas criam uma cadeia de retenção inquebrável.

Perguntas frequentes

Como o Strong Reference difere do Weak Reference?

Strong Reference incrementa o retain count do objeto e impede sua liberação enquanto a referência existir. Weak Reference não altera o retain count e se torna nil automaticamente quando o objeto é removido da memória. Referências fortes são usadas para propriedade, fracas para conexões inversas e delegados.

O que é um retain cycle e por que é perigoso?

Retain cycle é um bloqueio mútuo onde dois objetos se mantêm mutuamente com referências fortes. Seu retain count nunca chega a zero, a memória não é liberada. Isso leva a vazamentos de memória: os objetos permanecem no heap para sempre, a aplicação consome cada vez mais recursos e eventualmente trava com OutOfMemory.

Como detectar um retain cycle em uma aplicação iOS?

Use Instruments Leaks do Xcode — execute a criação de perfil com o template Leaks, execute um cenário no aplicativo e verifique os indicadores de vazamento. Para diagnóstico preciso, mude para a guia Cycles & Roots — ela mostra o gráfico de referências fortes mútuas que formam um ciclo inquebrável.

Quando usar Unowned em vez de Weak?

Unowned deve ser usado quando a vida do objeto filho garantidamente não excede a vida do pai — por exemplo, ao vincular um objeto a um escopo estritamente definido. Em caso de dúvida, use Weak, pois acessar uma referência unowned liberada causa um crash da aplicação.

As referências fortes afetam o desempenho da aplicação?

Indiretamente — sim. Cada retain e release no ARC é uma operação atômica com sobrecarga. Com um grande número de objetos em ciclos, isso pode afetar o desempenho. No entanto, o principal problema não é a velocidade do ARC, mas os vazamentos de memória devido a um tipo de referência mal escolhido.

Resumo

  • Strong Reference é o mecanismo básico de propriedade de objetos, mantendo-os na memória através do incremento do retain count.
  • ARC automatiza o gerenciamento de memória em Swift e Objective-C, eliminando retain e release manuais, mas não protege contra retain cycles.
  • Retain cycle ocorre com referências fortes mútuas — esta é a principal causa de vazamentos de memória em sistemas ARC.
  • As referências Weak e Unowned quebram ciclos de referências fortes sem incrementar o retain count.
  • A escolha do tipo de referência é determinada pela relação de propriedade: Strong para pai→filho, Weak ou Unowned para filho→pai.
  • Instruments Leaks e LeakCanary são as principais ferramentas para detectar referências fortes problemáticas em iOS e Android.
  • Projete o grafo de propriedade com antecedência — é mais barato do que corrigir vazamentos de memória após o lançamento da aplicação.

Vamos 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.

Discutir o projeto

Leia também