Sobes.tech
Middle

Quali tipi di riferimenti esistono in Swift?

sobes.tech AI

Risposta dell'AI

In Swift, ci sono tre principali tipi di riferimenti alle istanze delle classi:

  1. Riferimento forte (Strong Reference):

    • È il tipo di riferimento predefinito.
    • Un riferimento forte aumenta il contatore di riferimenti dell'oggetto.
    • L'oggetto non verrà rilasciato dalla memoria finché esiste almeno un riferimento forte.
    • La principale causa di perdite di memoria nei cicli di riferimenti forti (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) viene deallocato") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 ora è un riferimento forte, il contatore di riferimenti di Person aumenta
    
  2. Riferimento debole (Weak Reference):

    • Viene dichiarato usando la parola chiave weak.
    • Un riferimento debole non aumenta il contatore di riferimenti dell'oggetto.
    • Viene usato per prevenire strong reference cycles.
    • È sempre opzionale (Optional), perché l'oggetto a cui punta il riferimento debole può essere deallocato in qualsiasi momento. Quando l'oggetto viene deallocato, il riferimento debole diventa automaticamente nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Riferimento debole
        init(unit: String) { self.unit = unit }
        deinit { print("Appartamento \(unit) viene deallocato") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Se Apartment avesse un riferimento forte a Person
    unit4A?.tenant = john   // Riferimento debole
    
    // Dopo aver rimosso i riferimenti forti, gli oggetti verranno deallocati
    john = nil
    unit4A = nil
    // Output: "John viene deallocato", "Appartamento 4A viene deallocato"
    // Se tenant fosse un riferimento forte, si verificherebbe una perdita di memoria (cyclic cycle)
    
  3. Riferimento non posseduto (Unowned Reference):

    • Viene dichiarato usando la parola chiave unowned.
    • Simile al riferimento debole, non aumenta il contatore di riferimenti dell'oggetto.
    • Viene usato anche per prevenire strong reference cycles.
    • A differenza di weak, non è opzionale (Optional) e presuppone che l'oggetto a cui si riferisce esisterà per tutta la "durata di vita" del riferimento non posseduto.
    • Se l'oggetto a cui si riferisce unowned viene deallocato prima che il riferimento unowned diventi invalido, si verificherà un errore di runtime (runtime error).
    • È adatto per situazioni in cui un oggetto esiste sempre finché un altro oggetto correlato esiste (ad esempio, "genitore-figlio", dove il genitore possiede il bambino, ma il bambino non possiede il genitore in modo forte).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) viene deallocato") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Riferimento non posseduto
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Assegnazione sicura in init
        }
        deinit { print("Carta #\(number) viene deallocata") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Rimuovere il riferimento forte a Customer
    john = nil
    // Output: "John Doe viene deallocato", "Carta #1234567890123456 viene deallocata"
    // Il riferimento non posseduto in CreditCard era valido finché customer esisteva.
    // Se CreditCard durasse più di Customer e si tentasse di accedere a customer tramite il riferimento non posseduto, si verificherebbe un errore.
    

Differenza chiave tra weak e unowned:

  • weak: l'oggetto può essere nil. Usalo quando la durata di vita degli oggetti non è strettamente correlata (uno può esistere senza l'altro).
  • unowned: l'oggetto non può essere nil dopo l'inizializzazione. Usalo quando sei sicuro che l'oggetto referenziato esisterà almeno finché esiste l'oggetto che lo riferisce.