ProgrammazioneSviluppatore iOS

Che cos'è l'ARC in Swift? Come evitare i cicli di mantenimento quando si lavora con le closure e i delegati?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

ARC (Automatic Reference Counting) — sistema di gestione automatica della memoria in Swift. Ad ogni nuovo puntatore forte a un oggetto, il conteggio aumenta; quando viene rimosso, diminuisce. Quando il conteggio è zero, l'oggetto viene liberato.

Ciclo di mantenimento (retain cycle) — situazione in cui gli oggetti si riferiscono l'uno all'altro tramite riferimenti forti e non vengono mai liberati.

Modi per evitarlo:

  • Per oggetti delegati, usa un riferimento debole:
protocol SomeDelegate: AnyObject { } class Owner { weak var delegate: SomeDelegate? }
  • Per le closure usa [weak self] o [unowned self]:
class Example { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doSomething() } } func doSomething() { } }

Domanda trabocchetto.

Qual è la differenza tra [weak self] e [unowned self] all'interno di una closure? Quale tipo di riferimento utilizzare e quando?

Risposta:

  • [weak self] crea un riferimento opzionale; self può essere nil, quindi di solito si utilizza il recupero sicuro self?.
  • [unowned self] crea un riferimento non opzionale e NON aumenta il conteggio; se l'oggetto è già stato liberato e si verifica un accesso — si verificherà un crash.
  • La scelta dipende dalla logica di business: se la closure è garantita per vivere non più a lungo di self, si può utilizzare [unowned self].

Esempio:

someClosure = { [weak self] in self?.doTask() } // oppure (se self vive al 100% più a lungo della closure): someClosure = { [unowned self] in doTask() }

Esempi di errori reali dovuti alla scarsa conoscenza delle complessità del tema.


Storia

Nel progetto si è verificata una situazione di cicli di mantenimento tra ViewController e la sua closure legata alla gestione dei tocchi. ViewController si riferiva alla closure, che catturava self tramite riferimento forte. Di conseguenza, il controller e tutti i suoi dati non venivano liberati dopo la chiusura dello schermo. Il problema è stato risolto implementando [weak self] nella closure.


Storia

Implementazione del pattern delegato tra due oggetti. Il delegato è stato dichiarato come proprietà forte (strong). Di conseguenza, quando si tentava di rimuovere l'oggetto principale dalla memoria, non veniva deallocato, portando a una fuga di memoria. Dopo aver spostato il delegato su weak, il problema è scomparso.


Storia

Per l'animazione è stata utilizzata una closure all'interno di UIView. La closure catturava self con [unowned self]. Quando le viste venivano rimosse prima del completamento dell'animazione, l'app si chiudeva a causa di un accesso a self già liberato. La soluzione — utilizzo di [weak self] e verifica obbligatoria su self non nil all'interno della closure.