Sobes.tech
Middle

Come prevenite le perdite di memoria nei vostri progetti?

sobes.tech AI

Risposta dell'AI

Utilizzo diversi approcci:

  1. ARC (Contatore di riferimenti automatico): È il meccanismo principale di gestione della memoria in Swift e Objective-C. Conta automaticamente i riferimenti agli oggetti e li libera quando il conteggio raggiunge zero.
  2. Evitare cicli di riferimenti forti: Questa è la causa più comune di perdite di memoria. Uso riferimenti weak o unowned per interrompere i cicli. Questo accade spesso con delegati e closure.
  3. Strumenti di profiling: Uso regolarmente strumenti di Xcode, come Instruments (Allocator, Leaks), per individuare perdite.
  4. Verifica delle closure: Controllo attentamente le closure, specialmente quando catturo self, usando liste di cattura [weak self] o [unowned self].
  5. Disiscrizione dalle notifiche: Mi disiscrivo da NotificationCenter e dagli osservatori KVO quando gli oggetti vengono distrutti.
  6. Rimozione di osservatori e timer: Disattivo e azzero i timer invalidi e rimuovo gli osservatori quando non sono più necessari.
  7. Gestione delle risorse: Gestisco correttamente risorse come file, socket e database, chiudendoli e liberandoli tempestivamente.
  8. Revisioni del codice: Effettuo regolarmente revisioni del codice, anche per individuare potenziali problemi di gestione della memoria.

Esempio di utilizzo di [weak self] in una closure:

class DataFetcher {
    var completionHandler: (() -> Void)?

    func fetchData() {
        // Uso di weak self per evitare ciclo forte
        DispatchQueue.global().async { [weak self] in
            // Simulazione di recupero dati
            sleep(1)

            DispatchQueue.main.async {
                // Verifica di nil prima di usare self
                self?.completionHandler?()
            }
        }
    }
}

class ViewController {
    var fetcher: DataFetcher?

    func setupFetcher() {
        fetcher = DataFetcher()
        fetcher?.completionHandler = {
            // Qui, self può essere debole se fetcher esiste ancora
            print("Dati recuperati in ViewController")
        }
    }

    deinit {
        print("ViewController deallocato")
    }
}

Esempio di utilizzo di weak per un delegate:

protocol DataProcessorDelegate: AnyObject { // AnyObject garantisce il tipo di riferimento e impedisce cicli forti con tipi di valore
    func processData(_ data: String)
}

class DataProcessor {
    weak var delegate: DataProcessorDelegate? // Uso di weak per il delegate

    func process(_ data: String) {
        delegate?.processData(data)
    }
}

class AnotherViewController: DataProcessorDelegate {
    let processor = DataProcessor()

    init() {
        processor.delegate = self
    }

    func processData(_ data: String) {
        print("Elaborazione dati: \(data)")
    }

    deinit {
        print("AnotherViewController deallocato")
    }
}