Sobes.tech
Middle

O que é unowned na linguagem Swift e como é usado?

sobes.tech IA

Resposta da IA

A referência não possuída (gestão indireta fraca) em Swift é usada para evitar ciclos de retenção forte (retain cycles), quando dois objetos referenciam-se mutuamente de forma forte, impedindo a sua libertação de memória.

Características do unowned:

  • Garante que o objeto ao qual a referência unowned se refere existe sempre até ao momento de usar essa referência.
  • Se tentar aceder à referência unowned após o objeto associado ter sido libertado, ocorrerá um erro em tempo de execução (runtime crash).
  • É usado quando o ciclo de vida do objeto que faz a referência não é mais longo do que o ciclo de vida do objeto ao qual se refere. Ou seja, a referência com unowned não torna o objeto mais forte.

Exemplo de uso na captura de encerramento:

class Customer {
    let name: String
    var card: CreditCard?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) está a ser desalojado")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Referência não possuída a Customer

    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }

    deinit {
        print("Cartão #\(number) está a ser desalojado")
    }
}

var john: Customer? // Customer opcional para permitir libertação
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Atribuir nil a john levará à libertação de Customer e Card,
// pois não há ciclo de retenção forte
john = nil 

Outro exemplo - uso de unowned na lista de captura de encerramento:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [unowned self] in // Uso de unowned self
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) está a ser desalojado")
    }
}

var paragraph: HTMLElement? // Elemento HTML opcional
paragraph = HTMLElement(name: "p", text: "olá mundo")
print(paragraph!.asHTML())

// Atribuir nil libertará HTMLElement, pois a clausura não o mantém fortemente
paragraph = nil

A escolha entre unowned e weak depende de se a referência pode ser nil durante a vida do objeto. Se a referência nunca pode tornar-se nil antes da libertação do objeto, use unowned. Se pode, use weak.