Condividi tramite


Panoramica dell'API unificata

L'API unificata di Xamarin consente di condividere il codice tra Mac e iOS e supportare applicazioni a 32 e a 64 bit con lo stesso file binario. L'API unificata viene usata per impostazione predefinita nei nuovi progetti Xamarin.iOS e Xamarin.Mac.

Importante

L'API classica di Xamarin, che precedeva l'API unificata, è stata deprecata.

  • L'ultima versione di Xamarin.iOS per supportare l'API classica (monotouch.dll) era Xamarin.iOS 9.10.
  • Xamarin.Mac supporta ancora l'API classica, ma non viene più aggiornata. Poiché è deprecato, gli sviluppatori devono spostare le applicazioni nell'API unificata.

Aggiornamento di app basate su API classiche

Seguire le istruzioni pertinenti per la piattaforma:

Suggerimenti per l'aggiornamento del codice per l'API unificata

Indipendentemente dalle applicazioni di cui si esegue la migrazione, consultare questi suggerimenti per facilitare l'aggiornamento all'API unificata.

Divisione libreria

Da questo punto in poi, le API verranno visualizzate in due modi:

  • API classica: limitata a 32 bit (solo) ed esposta negli monotouch.dll assembly e XamMac.dll .
  • API unificata: supporta lo sviluppo a 32 e a 64 bit con una singola API disponibile negli Xamarin.iOS.dll assembly e Xamarin.Mac.dll .

Ciò significa che per gli sviluppatori aziendali (non destinati all'App Store), è possibile continuare a usare le API classiche esistenti, perché le manterranno per sempre oppure è possibile eseguire l'aggiornamento alle nuove API.

Modifiche dello spazio dei nomi

Per ridurre l'attrito per condividere il codice tra i prodotti Mac e iOS, vengono modificati gli spazi dei nomi per le API nei prodotti.

Stiamo eliminando il prefisso "MonoTouch" dal prodotto iOS e "MonoMac" dal prodotto Mac sui tipi di dati.

In questo modo è più semplice condividere il codice tra le piattaforme Mac e iOS senza ricorrere alla compilazione condizionale e ridurrà il rumore all'inizio dei file di codice sorgente.

  • API classica: gli spazi dei nomi usano o MonoMac. prefissiMonoTouch..
  • API unificata: nessun prefisso dello spazio dei nomi

Impostazioni predefinite del runtime

Per impostazione predefinita, l'API unificata usa il Garbage Collector SGen e il nuovo sistema di conteggio dei riferimenti per tenere traccia della proprietà degli oggetti. Questa stessa funzionalità è stata con portata a Xamarin.Mac.

In questo modo si risolve un certo numero di problemi che gli sviluppatori affrontano con il vecchio sistema e semplificano anche la gestione della memoria.

Si noti che è possibile abilitare New Refcount anche per l'API classica, ma il valore predefinito è conservativo e non richiede agli utenti di apportare modifiche. Con l'API unificata, abbiamo avuto l'opportunità di modificare l'impostazione predefinita e offrire agli sviluppatori tutti i miglioramenti contemporaneamente al refactoring e al nuovo test del codice.

Modifiche dell'API

L'API unificata rimuove i metodi deprecati e esistono alcune istanze in cui sono presenti errori di digitazioni nei nomi api quando sono stati associati agli spazi dei nomi MonoTouch e MonoMac originali nelle API classiche. Queste istanze sono state corrette nelle nuove API unificate e dovranno essere aggiornate nelle applicazioni componenti, iOS e Mac. Ecco un elenco dei più comuni che potresti riscontrare:

Nome metodo API classico Unified API Method Name
UINavigationController.PushViewControllerAnimated() UINavigationController.PushViewController()
UINavigationController.PopViewControllerAnimated() UINavigationController.PopViewController()
CGContext.SetRGBFillColor() CGContext.SetFillColor()
NetworkReachability.SetCallback() NetworkReachability.SetNotification()
CGContext.SetShadowWithColor CGContext.SetShadow
UIView.StringSize UIKit.UIStringDrawing.StringSize

Per un elenco completo delle modifiche quando si passa dalla versione classica all'API unificata, vedere la documentazione relativa alle differenze tra api classiche (monotouch.dll) e unificate (Xamarin.iOS.dll).

Aggiornamento a Unified

Diverse API obsolete/interrotte/deprecate nella versione classica non sono disponibili nell'API unificata . Può essere più semplice correggere gli avvisi prima di avviare l'aggiornamento CS0616 (manuale o automatizzato) perché si avrà il [Obsolete] messaggio di attributo (parte dell'avviso) per guidare l'utente all'API corretta.

Si noti che stiamo pubblicando una differenza delle modifiche api classiche e unificate che possono essere usate prima o dopo gli aggiornamenti del progetto. La correzione delle chiamate obsolete nella versione classica è spesso un risparmio di tempo (meno ricerche nella documentazione).

Seguire queste istruzioni per aggiornare le app iOS esistenti o Mac all'API unificata. Esaminare la parte restante di questa pagina e questi suggerimenti per altre informazioni sulla migrazione del codice.

NuGet

Pacchetti NuGet che in precedenza supportavano Xamarin.iOS tramite l'API classica pubblicarono gli assembly usando il moniker della piattaforma Monotouch10 .

L'API unificata introduce un nuovo identificatore della piattaforma per i pacchetti compatibili Xamarin.iOS10. I pacchetti NuGet esistenti dovranno essere aggiornati per aggiungere il supporto per questa piattaforma, compilando con l'API unificata.

Importante

Se si verifica un errore nel formato "Errore 3 Non è possibile includere sia 'monotouch.dll' che 'Xamarin.iOS.dll' nello stesso progetto Xamarin.iOS - Viene fatto riferimento in modo esplicito a 'Xamarin.iOS.dll', mentre 'monotouch.dll' viene fatto riferimento da 'xxx, Version=0.0.000, Culture=neutral, PublicKeyToken=null'" dopo aver convertito l'applicazione nelle API unificate, è in genere dovuto alla presenza di un componente o di un pacchetto NuGet nel progetto che non è stato aggiornato all'API unificata. È necessario rimuovere il componente/NuGet esistente, eseguire l'aggiornamento a una versione che supporta le API unificate ed eseguire una compilazione pulita.

La strada a 64 bit

Per informazioni generali sul supporto di applicazioni a 32 e 64 bit e informazioni sui framework, vedere Considerazioni sulla piattaforma a 32 e 64 bit.

Nuovi tipi di dati

Al centro della differenza, sia le API Mac che iOS usano tipi di dati specifici dell'architettura che sono sempre a 32 bit su piattaforme a 32 bit e 64 bit su piattaforme a 64 bit.

Ad esempio, Objective-C esegue il mapping del NSInteger tipo di dati a su sistemi a int32_t 32 bit e su su sistemi a int64_t 64 bit.

Per trovare la corrispondenza con questo comportamento, nell'API unificata si sostituiscono gli usi precedenti di int (che in .NET è sempre System.Int32definito come ) in un nuovo tipo di dati: System.nint. È possibile considerare "n" come "nativo", quindi il tipo integer nativo della piattaforma.

Stiamo introducendo ninte nuintnfloat fornendo anche tipi di dati basati su di essi, se necessario.

Per altre informazioni su queste modifiche ai tipi di dati, vedere il documento Tipi nativi.

Come rilevare l'architettura delle app iOS

In alcune situazioni l'applicazione deve sapere se è in esecuzione in un sistema iOS a 32 bit o a 64 bit. Per controllare l'architettura, è possibile usare il codice seguente:

if (IntPtr.Size == 4) {
    Console.WriteLine ("32-bit App");
} else if (IntPtr.Size == 8) {
    Console.WriteLine ("64-bit App");
}

Matrici e System.Collections.Generic

Poiché gli indicizzatori C# prevedono un tipo di int, è necessario eseguire il cast nint esplicito dei valori per accedere agli int elementi in una raccolta o in una matrice. Ad esempio:

public List<string> Names = new List<string>();
...

public string GetName(nint index) {
    return Names[(int)index];
}

Si tratta di un comportamento previsto, perché il cast da int a nint è in perdita a 64 bit, non viene eseguita una conversione implicita.

Conversione di DateTime in NSDate

Quando si usano le API unificate, la conversione implicita di DateTime in NSDate valori non viene più eseguita. Questi valori dovranno essere convertiti in modo esplicito da un tipo a un altro. Per automatizzare questo processo, è possibile usare i metodi di estensione seguenti:

public static DateTime NSDateToDateTime(this NSDate date)
{
    // NSDate has a wider range than DateTime, so clip
    // the converted date to DateTime.Min|MaxValue.
    double secs = date.SecondsSinceReferenceDate;
    if (secs < -63113904000)
        return DateTime.MinValue;
    if (secs > 252423993599)
        return DateTime.MaxValue;
    return (DateTime) date;
}

public static NSDate DateTimeToNSDate(this DateTime date)
{
    if (date.Kind == DateTimeKind.Unspecified)
        date = DateTime.SpecifyKind (date, /* DateTimeKind.Local or DateTimeKind.Utc, this depends on each app */)
    return (NSDate) date;
}

API e errori di digitazioni deprecati

All'interno dell'API classica Xamarin.iOS (monotouch.dll) l'attributo [Obsolete] è stato usato in due modi diversi:

  • API iOS deprecata: quando Apple suggerisce di smettere di usare un'API perché viene sostituita da una versione più recente. L'API classica è ancora corretta e spesso necessaria (se si supporta la versione precedente di iOS). Tali API (e l'attributo [Obsolete] ) vengono incluse nei nuovi assembly Xamarin.iOS.
  • API errata Alcune API avevano errori di digitazioni sui nomi.

Per gli assembly originali (monotouch.dll e XamMac.dll) è stato mantenuto disponibile il codice precedente per la compatibilità, ma sono stati rimossi dagli assembly dell'API unificata (Xamarin.iOS.dll e Xamarin.Mac)

Sottoclassi NSObject .ctor(IntPtr)

Ogni NSObject sottoclasse ha un costruttore che accetta un oggetto IntPtr. Questo è il modo in cui è possibile creare un'istanza di una nuova istanza gestita da un handle ObjC nativo.

In classico questo era un public costruttore. Tuttavia, è stato facile usare in modo improprio questa funzionalità nel codice utente, ad esempio creando diverse istanze gestite per una singola istanza ObjC o creando un'istanza gestita che non avrebbe lo stato gestito previsto (per le sottoclassi).

Per evitare questi tipi di problemi, i IntPtr costruttori sono ora protected nell'API unificata , da usare solo per la sottoclasse. In questo modo si garantisce che l'API corretta/sicura venga usata per creare un'istanza gestita da handle, ad esempio

var label = Runtime.GetNSObject<UILabel> (handle);

Questa API restituirà un'istanza gestita esistente (se già esistente) o ne creerà una nuova (se necessario). È già disponibile nell'API classica e unificata.

Si noti che .ctor(NSObjectFlag) è ora anche protected ma questo è stato usato raramente al di fuori della sottoclasse.

NSAction sostituito con l'azione

Con le API unificate, NSAction è stato rimosso a favore di .NET Actionstandard. Si tratta di un miglioramento significativo perché Action è un tipo .NET comune, mentre NSAction era specifico di Xamarin.iOS. Entrambe eseguono esattamente la stessa operazione, ma erano tipi distinti e incompatibili e hanno comportato la necessità di scrivere più codice per ottenere lo stesso risultato.

Ad esempio, se l'applicazione Xamarin esistente include il codice seguente:

UITapGestureRecognizer singleTap = new UITapGestureRecognizer (new NSAction (delegate() {
    ShowDropDownAnimated (tblDataView);
}));

Ora può essere sostituito con una semplice espressione lambda:

UITapGestureRecognizer singleTap = new UITapGestureRecognizer (() => ShowDropDownAnimated(tblDataView));

In precedenza si tratta di un errore del compilatore perché non è possibile assegnare a ActionNSAction, ma poiché UITapGestureRecognizer ora accetta un anziché un NSActionAction valore valido nelle API unificate.

Delegati personalizzati sostituiti con Action<T>

In alcuni delegati semplici (ad esempio un parametro) .net sono stati sostituiti con Action<T>. ad esempio

public delegate void NSNotificationHandler (NSNotification notification);

può ora essere usato come Action<NSNotification>. In questo modo si promuove il riutilizzo del codice e si riduce la duplicazione del codice sia in Xamarin.iOS che nelle proprie applicazioni.

Attività<bool> sostituita con Task<Boolean,N edizione Standard rror>>

Nella versione classica sono state restituite alcune API asincrone che Task<bool>restituiscono . Tuttavia, alcuni di essi dove devono essere usati quando un NSError elemento faceva parte della firma, ad esempio bool era già true e dovevi rilevare un'eccezione per ottenere .NSError

Poiché alcuni errori sono molto comuni e il valore restituito non è stato utile, questo modello è stato modificato in unificato per restituire un oggetto Task<Tuple<Boolean,NSError>>. In questo modo è possibile controllare sia l'esito positivo che qualsiasi errore che potrebbe essersi verificato durante la chiamata asincrona.

NSString e string

In alcuni casi alcune costanti devono essere modificate da string a NSString, ad esempio UITableViewCell

Classico

public virtual string ReuseIdentifier { get; }

Unified

public virtual NSString ReuseIdentifier { get; }

In generale, si preferisce il tipo .NET System.String . Tuttavia, nonostante le linee guida di Apple, alcune API native confrontano puntatori costanti (non la stringa stessa) e questo può funzionare solo quando si espongono le costanti come NSString.

Objective-C Protocolli

L'originale MonoTouch non aveva il supporto completo per i protocolli ObjC e alcune API, non ottimali, sono state aggiunte per supportare lo scenario più comune. Questa limitazione non esiste più, ma, per la compatibilità con le versioni precedenti, diverse API vengono mantenute all'interno monotouch.dll di e XamMac.dll.

Queste limitazioni sono state rimosse e eliminate nelle API unificate. La maggior parte delle modifiche avrà un aspetto simile al seguente:

Classico

public virtual AVAssetResourceLoaderDelegate Delegate { get; }

Unified

public virtual IAVAssetResourceLoaderDelegate Delegate { get; }

Il I prefisso significa esporre un'interfaccia unificata, anziché un tipo specifico, per il protocollo ObjC. In questo modo, i casi in cui non si vuole sottoclassare il tipo specifico fornito da Xamarin.iOS.

Inoltre, alcune API possono essere più precise e facili da usare, ad esempio:

Classico

public virtual void SelectionDidChange (NSObject uiTextInput);

Unified

public virtual void SelectionDidChange (IUITextInput uiTextInput);

Queste API sono ora più facili da usare, senza fare riferimento alla documentazione e il completamento del codice dell'IDE fornirà suggerimenti più utili in base al protocollo/interfaccia.

Protocollo NSCoding

L'associazione originale includeva un .ctor(NSCoder) per ogni tipo, anche se non supportava il NSCoding protocollo. Un singolo Encode(NSCoder) metodo era presente in NSObject per codificare l'oggetto. Tuttavia, questo metodo funziona solo se l'istanza è conforme al protocollo NSCoding.

Nell'API unificata è stato risolto questo problema. I nuovi assembly avranno solo .ctor(NSCoder) se il tipo è conforme a NSCoding. Anche questi tipi ora dispongono di un Encode(NSCoder) metodo conforme all'interfaccia INSCoding .

Basso impatto: nella maggior parte dei casi questa modifica non influisce sulle applicazioni perché non è stato possibile usare i costruttori precedenti, rimossi.

Ulteriori Suggerimenti

Altre modifiche da tenere presenti sono elencate nei suggerimenti per aggiornare le app all'API unificata.