Sobes.tech
Middle

Quali sono i tipi di riferimenti in Swift?

sobes.tech AI

Risposta dell'AI

In Swift, ci sono tre principali tipi di riferimenti:

  1. **Riferimento Forte (Strong Reference):

    • Aumenta il contatore di riferimenti dell'oggetto.
    • Impedisce la deallocazione dell'oggetto finché esiste almeno un riferimento forte.
    • È il tipo di riferimento predefinito in Swift.
    • La causa principale di cicli di riferimenti forti.
  2. **Riferimento Debole (Weak Reference):

    • Non aumenta il contatore di riferimenti.
    • Permette la deallocazione dell'oggetto se non ci sono più riferimenti forti.
    • Viene dichiarato usando la parola chiave weak.
    • È sempre opzionale (Optional), poiché l'oggetto referenziato può diventare nil.
    • Viene usato per prevenire cicli di riferimenti forti, quando un'istanza può esistere indipendentemente dall'altra.
    class Person {
        let name: String
        weak var apartment: Apartment? // Riferimento debole
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) deallocato") }
    }
    
    class Apartment {
        let unit: String
        var tenant: Person? // Riferimento forte normale
        init(unit: String) {
            self.unit = unit
        }
        deinit { print("Appartamento \(unit) deallocato") }
    }
    
    var john: Person?
    var unit4A: Apartment?
    
    john = Person(name: "John Appleseed")
    unit4A = Apartment(unit: "4A")
    
    john!.apartment = unit4A
    unit4A!.tenant = john // Qui si potrebbe creare un ciclo di riferimenti forti senza weak
    
    // Le referenze vengono azzerate, gli oggetti deallocati
    john = nil
    unit4A = nil
    
  3. **Riferimento Non Posseduto (Unowned Reference):

    • Non aumenta il contatore di riferimenti.
    • Permette la deallocazione dell'oggetto se non ci sono più riferimenti forti.
    • Viene dichiarato usando la parola chiave unowned.
    • Non è opzionale. Si presume che l'oggetto referenziato esisterà sempre finché esiste l'istanza che contiene il riferimento non posseduto.
    • L'uso di un riferimento non posseduto su un oggetto già deallocato causerà un errore in fase di esecuzione (crash).
    • Viene usato per prevenire cicli di riferimenti forti, quando un'istanza deve sempre esistere finché un'altra esiste, e non c'è possibilità che uno dei due diventi nil indipendentemente dall'altro (ad esempio, in chiusure con self).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) deallocato") }
    }
    
    class CreditCard {
        let number: UInt64
        unowned let customer: Customer // Riferimento non posseduto
        init(number: UInt64, customer: Customer) {
            self.number = number
            self.customer = customer
        }
        deinit { print("Carta #\(number) deallocata") }
    }
    
    var john: Customer? = Customer(name: "John Appleseed")
    john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Se si annulla il cliente, la carta che fa riferimento a lui con unowned,
    // diventerà invalida, ma non causerà ciclo.
    john = nil // Entrambi gli oggetti vengono deallocati
    

La scelta tra weak e unowned dipende dalla natura della relazione tra gli oggetti: usa weak quando un oggetto può esistere senza l'altro (Person senza Apartment), e unowned quando un oggetto deve sempre esistere finché l'altro esiste (CreditCard appartiene sempre a Customer).