Sobes.tech
Middle

Que tipos de ligações existem em Swift?

sobes.tech IA

Resposta da IA

Em Swift, existem três tipos principais de referências a instâncias de classes:

  1. Referência forte (Strong Reference):

    • É o tipo padrão de referência.
    • A referência forte aumenta o contador de referências do objeto.
    • O objeto não será liberado da memória enquanto existir pelo menos uma referência forte.
    • A principal causa de vazamentos de memória em ciclos de referências fortes (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) está sendo desinicializado") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 agora é uma referência forte, o contador de referências de Person aumenta
    
  2. Referência fraca (Weak Reference):

    • Declarada usando a palavra-chave weak.
    • A referência fraca não aumenta o contador de referências do objeto.
    • Usada para prevenir ciclos de referências fortes (strong reference cycles).
    • Sempre é opcional (Optional), porque o objeto apontado pela referência fraca pode ser destruído a qualquer momento. Quando o objeto é destruído, a referência fraca automaticamente se torna nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Referência fraca
        init(unit: String) { self.unit = unit }
        deinit { print("Apartamento \(unit) está sendo desinicializado") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Se Apartment tivesse uma referência forte a Person
    unit4A?.tenant = john   // Referência fraca
    
    // Após remover as referências fortes, os objetos serão desinicializados
    john = nil
    unit4A = nil
    // Saída: "John está sendo desinicializado", "Apartamento 4A está sendo desinicializado"
    // Se tenant fosse uma referência forte, ocorreria uma fuga de memória (cycle forte)
    
  3. Referência não possuída (Unowned Reference):

    • Declarada usando a palavra-chave unowned.
    • Semelhante à referência fraca, não aumenta o contador de referências do objeto.
    • Também usada para prevenir ciclos de referências fortes.
    • Ao contrário de weak, não é opcional (Optional) e supõe que o objeto ao qual ela aponta existirá durante toda a "vida" da referência não possuída.
    • Se o objeto ao qual a referência unowned aponta for destruído antes que a referência unowned se torne inválida, ocorrerá um erro em tempo de execução (runtime error).
    • Adequada para situações onde um objeto sempre existe enquanto outro objeto relacionado também exista (por exemplo, "pai-filho", onde o pai possui o filho, mas o filho não possui o pai de forma forte).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) está sendo desinicializado") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Referência não possuída
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Atribuição segura em init
        }
        deinit { print("Cartão #\(number) está sendo desinicializado") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Remover a referência forte a Customer
    john = nil
    // Saída: "John Doe está sendo desinicializado", "Cartão #1234567890123456 está sendo desinicializado"
    // A referência não possuída em CreditCard era válida enquanto customer existia.
    // Se CreditCard durasse mais que Customer e tentássemos acessar customer através da referência não possuída, ocorreria um erro.
    

Diferença chave entre weak e unowned:

  • weak: o objeto pode ser nil. Use quando a duração de vida dos objetos não estiver estritamente relacionada (um pode existir sem o outro).
  • unowned: o objeto não pode ser nil após a inicialização. Use quando tiver certeza de que o objeto referenciado existirá pelo menos até que o objeto que faz referência a ele exista.