Nuovo sistema di conteggio dei riferimenti in Xamarin.iOS

Xamarin.iOS 9.2.1 ha introdotto il sistema di conteggio dei riferimenti avanzato per tutte le applicazioni per impostazione predefinita. Può essere usato per eliminare molti problemi di memoria difficili da tenere traccia e correggere nelle versioni precedenti di Xamarin.iOS.

Abilitazione del nuovo sistema di conteggio dei riferimenti

A partire da Xamarin 9.2.1 il nuovo sistema di conteggio dei riferimenti è abilitato per tutte le applicazioni per impostazione predefinita.

Se si sviluppa un'applicazione esistente, è possibile controllare il file con estensione csproj per assicurarsi che tutte le occorrenze di MtouchUseRefCounting siano impostate su true, come indicato di seguito:

<MtouchUseRefCounting>true</MtouchUseRefCounting>

Se è impostato sull'applicazione false , non verrà usato il nuovo strumento.

Uso delle versioni precedenti di Xamarin

Xamarin.iOS 7.2.1 e versioni successive offre un'anteprima avanzata del nuovo sistema di conteggio dei riferimenti.

API classica:

Per abilitare questo nuovo sistema di conteggio dei riferimenti, selezionare la casella di controllo Usa l'estensione di conteggio dei riferimenti disponibile nella scheda Avanzate delle opzioni di compilazione iOS del progetto, come illustrato di seguito:

Enable the new Reference Counting System

Si noti che queste opzioni sono state rimosse nelle versioni più recenti di Visual Studio per Mac.

API unificata:

La nuova estensione per il conteggio dei riferimenti è necessaria per l'API unificata e deve essere abilitata per impostazione predefinita. Le versioni precedenti dell'IDE potrebbero non avere questo valore controllato automaticamente e potrebbe essere necessario effettuare un controllo manualmente.

Importante

Una versione precedente di questa funzionalità è stata intorno a monoTouch 5.2, ma era disponibile solo per sgen come anteprima sperimentale. Questa nuova versione avanzata è ora disponibile anche per il Garbage Collector boehm .

Storicamente esistono due tipi di oggetti gestiti da Xamarin.iOS: quelli che erano semplicemente un wrapper intorno a un oggetto nativo (oggetti peer) e quelli che hanno esteso o incorporato nuove funzionalità (oggetti derivati), in genere mantenendo uno stato in memoria aggiuntivo. In precedenza era possibile aumentare un oggetto peer con stato (ad esempio aggiungendo un gestore eventi C#), ma che l'oggetto passasse senza riferimenti e quindi raccolto. Questo potrebbe causare un arresto anomalo in un secondo momento( ad esempio, se il Objective-C runtime ha chiamato nuovamente nell'oggetto gestito).

Il nuovo sistema aggiorna automaticamente gli oggetti peer in oggetti gestiti dal runtime quando archiviano informazioni aggiuntive.

In questo modo vengono risolti vari arresti anomali che si sono verificati in situazioni come questa:

class MyTableSource : UITableViewSource {
   public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) {
        var cell = tableView.DequeueReusableCell ("myId");
        if (cell != null)
                return cell;

        cell = new UITableViewCell (UITableViewCellStyle.Default, "myId");
        var txt = new UITextField ();
        txt.TouchDown += delegate { Console.WriteLine ("...."); };
        cell.ContentView.AddSubview (txt);
        return cell;
   }
}

Senza l'estensione del conteggio dei riferimenti questo codice si arresterebbe in modo anomalo perché cell diventa raccoglibile e quindi il relativo TouchDown delegato, che si tradurrà in un puntatore incerto.

L'estensione del conteggio dei riferimenti garantisce che l'oggetto gestito rimanga attivo e ne impedisca la raccolta, purché l'oggetto nativo venga mantenuto dal codice nativo.

Il nuovo sistema elimina anche la necessità di usare la maggior parte dei campi di backup privati nelle associazioni, ovvero l'approccio predefinito per mantenere attiva l'istanza. Il linker gestito è abbastanza intelligente da rimuovere tutti i campi non necessari dalle applicazioni usando la nuova estensione del conteggio dei riferimenti.

Ciò significa che ogni istanza dell'oggetto gestito utilizza meno memoria di prima. Risolve anche un problema correlato in cui alcuni campi di backup contengono riferimenti che non erano più necessari dal Objective-C runtime, rendendo difficile recuperare memoria.