Übersicht über die einheitliche API
Die einheitliche API von Xamarin ermöglicht es, Code zwischen Mac und iOS gemeinsam zu nutzen und 32- und 64-Bit-Anwendungen mit derselben Binärdatei zu unterstützen. Die einheitliche API wird standardmäßig in neuen Xamarin.iOS- und Xamarin.Mac-Projekten verwendet.
Wichtig
Die klassische Xamarin-API, die der einheitlichen API vorausging, ist veraltet.
- Die letzte Version von Xamarin.iOS, die die klassische API (monotouch.dll) unterstützt, war Xamarin.iOS 9.10.
- Xamarin.Mac unterstützt weiterhin die klassische API, wird aber nicht mehr aktualisiert. Da sie veraltet ist, sollten Entwickler ihre Anwendungen in die einheitliche API verschieben.
Aktualisieren klassischer API-basierter Apps
Befolgen Sie die entsprechenden Anweisungen für Ihre Plattform:
- Aktualisieren von vorhandenen Apps
- Aktualisieren von vorhandenen iOS-Apps
- Aktualisieren von vorhandenen Mac-Apps
- Aktualisieren von vorhandenen Xamarin.Forms-Apps
- Migrieren einer Bindung zu Unified API
Tipps zum Aktualisieren von Code für Unified API
Unabhängig davon, welche Anwendungen Sie migrieren, lesen Sie diese Tipps , damit Sie erfolgreich auf die einheitliche API aktualisieren können.
Bibliotheksaufteilung
Ab diesem Punkt werden unsere APIs auf zwei Arten angezeigt:
- Klassische API: Auf 32-Bits (nur) beschränkt und in den
monotouch.dll
Assemblys undXamMac.dll
verfügbar gemacht. - Einheitliche API: Unterstützen Sie sowohl die 32- als auch die 64-Bit-Entwicklung mit einer einzelnen API, die in den
Xamarin.iOS.dll
Assemblys undXamarin.Mac.dll
verfügbar ist.
Dies bedeutet, dass Sie für Unternehmensentwickler (die nicht auf die App Store ausgerichtet sind) die vorhandenen klassischen APIs weiterhin verwenden können, da sie für immer beibehalten werden, oder Sie können ein Upgrade auf die neuen APIs durchführen.
Namespaceänderungen
Um die Reibung beim Freigeben von Code zwischen unseren Mac- und iOS-Produkten zu verringern, ändern wir die Namespaces für die APIs in den Produkten.
Wir löschen das Präfix "MonoTouch" aus unserem iOS-Produkt und "MonoMac" aus unserem Mac-Produkt für die Datentypen.
Dies vereinfacht das Freigeben von Code zwischen den Mac- und iOS-Plattformen, ohne auf die bedingte Kompilierung zurückgreifen zu müssen, und reduziert das Rauschen am Anfang Ihrer Quellcodedateien.
- Klassische API: Namespaces verwenden
MonoTouch.
oderMonoMac.
präfix. - Einheitliche API: Kein Namespacepräfix
Laufzeitstandardeinstellungen
Die einheitliche API verwendet standardmäßig den Garbage Collector SGen und das Neue Verweiszählungssystem für die Nachverfolgung des Objektbesitzes. Das gleiche Feature wurde zu Xamarin.Mac portiert.
Dies löst eine Reihe von Problemen, die Entwickler mit dem alten System konfrontiert haben, und erleichtert auch die Speicherverwaltung.
Beachten Sie, dass es möglich ist, neue Refcount auch für die klassische API zu aktivieren, aber der Standardwert ist konservativer Wert und erfordert keine Änderungen durch Benutzer. Mit der einheitlichen API haben wir die Gelegenheit genutzt, die Standardeinstellung zu ändern und Entwicklern alle Verbesserungen zu bieten, während sie ihren Code umgestalten und erneut testen.
API-Änderungen
Die Einheitliche API entfernt veraltete Methoden, und es gibt einige Instanzen, in denen tippfehler in den API-Namen aufgetreten sind, als sie an die ursprünglichen MonoTouch- und MonoMac-Namespaces in den klassischen APIs gebunden waren. Diese Instanzen wurden in den neuen einheitlichen APIs korrigiert und müssen in Ihren Komponenten-, iOS- und Mac-Anwendungen aktualisiert werden. Im Folgenden finden Sie eine Liste der häufigsten Vorkommen:
Name der klassischen API-Methode | Name der einheitlichen API-Methode |
---|---|
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 |
Eine vollständige Liste der Änderungen beim Wechsel von der klassischen zur einheitlichen API finden Sie in der Dokumentation zu den Unterschieden zwischen klassischen (monotouch.dll) und unified-API (Xamarin.iOS.dll).
Aktualisieren auf Unified
Mehrere alte/defekte/veraltete API im klassischen Modus sind in der einheitlichen API nicht verfügbar. Es kann einfacher sein, die CS0616
Warnungen zu beheben, bevor Sie ihr (manuelles oder automatisiertes) Upgrade starten, da Sie die [Obsolete]
Attributmeldung (Teil der Warnung) erhalten, um Sie zur richtigen API zu führen.
Beachten Sie, dass wir eine diff der klassischen und einheitlichen API-Änderungen veröffentlichen, die vor oder nach den Projektupdates verwendet werden können. Das Beheben veralteter Aufrufe in Classic ist häufig zeitsparend (weniger Dokumentationssuchen).
Befolgen Sie diese Anweisungen, um vorhandene iOS-Apps oder Mac-Apps auf die einheitliche API zu aktualisieren. Lesen Sie den Rest dieser Seite und diese Tipps , um zusätzliche Informationen zur Migration Ihres Codes zu erhalten.
NuGet
NuGet-Pakete, die zuvor Xamarin.iOS über die klassische API unterstützt haben, veröffentlichten ihre Assemblys mithilfe des Monotouch10-Plattformmonikers .
Die einheitliche API führt einen neuen Plattformbezeichner für kompatible Pakete ein : Xamarin.iOS10. Vorhandene NuGet-Pakete müssen aktualisiert werden, um Unterstützung für diese Plattform hinzuzufügen, indem sie mit der einheitlichen API erstellt werden.
Wichtig
Wenn der Fehler "Fehler 3 kann nicht sowohl "monotouch.dll" als auch "Xamarin.iOS.dll" im selben Xamarin.iOS-Projekt enthalten sein, wird explizit auf "Xamarin.iOS.dll" verwiesen, während "monotouch.dll" nach dem Konvertieren ihrer Anwendung in die einheitlichen APIs von "xxx, Version=0.0.000, Culture=neutral, PublicKeyToken=null" referenziert wird , liegt dies in der Regel daran, dass entweder eine Komponente oder ein NuGet-Paket im Projekt vorhanden ist, das nicht auf die einheitliche API aktualisiert wurde. Sie müssen die vorhandene Komponente/NuGet entfernen, auf eine Version aktualisieren, die die einheitlichen APIs unterstützt, und einen sauber Build durchführen.
Der Weg zu 64 Bits
Hintergrundinformationen zur Unterstützung von 32- und 64-Bit-Anwendungen sowie Informationen zu Frameworks finden Sie in den Überlegungen zur 32- und 64-Bit-Plattform.
Neue Datentypen
Im Kern des Unterschieds verwenden sowohl Mac- als auch iOS-APIs architekturspezifische Datentypen, die auf 32-Bit-Plattformen immer 32 Bit und 64 Bit auf 64-Bit-Plattformen sind.
Ordnet beispielsweise Objective-C den NSInteger
Datentyp int32_t
auf 32-Bit-Systemen und auf 64-Bit-Systemen zu int64_t
.
Um diesem Verhalten zu entsprechen, ersetzen wir in unserer einheitlichen API die vorherigen Verwendungen von int
(die in .NET als immer System.Int32
definiert ist) durch einen neuen Datentyp: System.nint
. Sie können sich "n" als "n" vorstellen, also den nativen Ganzzahltyp der Plattform.
Wir führen ein nint
nuint
und nfloat
stellen bei Bedarf darüber basierende Datentypen bereit.
Weitere Informationen zu diesen Datentypänderungen finden Sie im Dokument Native Typen .
Erkennen der Architektur von iOS-Apps
Es kann Situationen geben, in denen Ihre Anwendung wissen muss, ob sie auf einem 32-Bit- oder einem 64-Bit-iOS-System ausgeführt wird. Der folgende Code kann verwendet werden, um die Architektur zu überprüfen:
if (IntPtr.Size == 4) {
Console.WriteLine ("32-bit App");
} else if (IntPtr.Size == 8) {
Console.WriteLine ("64-bit App");
}
Arrays und System.Collections.Generic
Da C#-Indexer einen Typ von int
erwarten, müssen Sie Werte explizit in umwandeln nint
, int
um auf die Elemente in einer Auflistung oder einem Array zuzugreifen. Beispiel:
public List<string> Names = new List<string>();
...
public string GetName(nint index) {
return Names[(int)index];
}
Dies ist ein erwartetes Verhalten, da die Umwandlung von in int
nint
bei 64 Bit verlustbehaftet ist, eine implizite Konvertierung nicht durchgeführt wird.
Konvertieren von DateTime in NSDate
Bei Verwendung der einheitlichen APIs wird die implizite Konvertierung von DateTime
nicht mehr in NSDate
Werte ausgeführt. Diese Werte müssen explizit von einem Typ in einen anderen konvertiert werden. Die folgenden Erweiterungsmethoden können verwendet werden, um diesen Prozess zu automatisieren:
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;
}
Veraltete APIs und Tippfehler
Innerhalb der klassischen Xamarin.iOS-API (monotouch.dll) wurde das [Obsolete]
Attribut auf zwei verschiedene Arten verwendet:
- Veraltete iOS-API: Dies ist der Zeitpunkt, an dem Apple Ihnen angibt, die Verwendung einer API zu beenden, da sie von einer neueren abgelöst wird. Die klassische API ist immer noch in Ordnung und häufig erforderlich (wenn Sie die ältere Version von iOS unterstützen).
Diese API (und das
[Obsolete]
Attribut) sind in den neuen Xamarin.iOS-Assemblys enthalten. - Falsche API Einige API hatte Tippfehler in ihren Namen.
Für die ursprünglichen Assemblys (monotouch.dll und XamMac.dll) haben wir den alten Code aus Kompatibilitätsgründen verfügbar gehalten, sie wurden jedoch aus den Assemblys der einheitlichen API (Xamarin.iOS.dll und Xamarin.Mac) entfernt.
NSObject-Unterklassen .ctor(IntPtr)
Jede NSObject
Unterklasse verfügt über einen Konstruktor, der ein IntPtr
akzeptiert. So können wir eine neue verwaltete instance aus einem nativen ObjC-Handle instanziieren.
Im klassischen Modus war dies ein public
Konstruktor. Es war jedoch leicht, dieses Feature im Benutzercode zu missbrauchen, z. B. das Erstellen mehrerer verwalteter Instanzen für eine einzelne ObjC-instance oder das Erstellen eines verwalteten instance, dem der erwartete verwaltete Zustand (für Unterklassen) fehlte.
Um solche Probleme zu vermeiden, befinden sich die IntPtr
Konstruktoren jetzt protected
in einer einheitlichen API, die nur für Unterklassen verwendet werden soll. Dadurch wird sichergestellt, dass die richtige/sichere API verwendet wird, um verwaltete instance aus Handles zu erstellen, z. B.
var label = Runtime.GetNSObject<UILabel> (handle);
Diese API gibt eine vorhandene verwaltete instance zurück (sofern bereits vorhanden) oder erstellt (falls erforderlich) eine neue. Es ist bereits in der klassischen und einheitlichen API verfügbar.
Beachten Sie, dass die .ctor(NSObjectFlag)
jetzt auch protected
ist, aber diese wurde nur selten außerhalb der Unterklasse verwendet.
NSAction durch Aktion ersetzt
Mit den einheitlichen APIs NSAction
wurde zugunsten des .NET-Standards Action
entfernt. Dies ist eine große Verbesserung, da Action
es sich um einen allgemeinen .NET-Typ handelt, während NSAction
es sich um einen spezifischen Xamarin.iOS-Typ handelt. Beide machen genau dasselbe, aber sie waren unterschiedliche und inkompatible Typen und führten dazu, dass mehr Code geschrieben werden musste, um dasselbe Ergebnis zu erzielen.
Beispiel: Ihre vorhandene Xamarin-Anwendung enthält den folgenden Code:
UITapGestureRecognizer singleTap = new UITapGestureRecognizer (new NSAction (delegate() {
ShowDropDownAnimated (tblDataView);
}));
Es kann jetzt durch ein einfaches Lambda ersetzt werden:
UITapGestureRecognizer singleTap = new UITapGestureRecognizer (() => ShowDropDownAnimated(tblDataView));
Früher war dies ein Compilerfehler, da ein Action
nicht zugewiesen NSAction
werden kann, aber da UITapGestureRecognizer
jetzt ein Action
anstelle eines NSAction
verwendet wird, ist es in den einheitlichen APIs gültig.
Benutzerdefinierte Delegaten, die durch Aktion<T ersetzt wurden>
In einheitlichen einfachen (z. B. einem Parameter) wurden .net-Delegaten durch Action<T>
ersetzt. Beispiel:
public delegate void NSNotificationHandler (NSNotification notification);
kann jetzt als Action<NSNotification>
verwendet werden. Dies fördert die Wiederverwendung von Code und verringert die Duplizierung von Code sowohl in Xamarin.iOS als auch in Ihren eigenen Anwendungen.
Aufgabe<bool> ersetzt durch Task<Boolean,NSError>>
Im klassischen Modus gab es einige asynchrone APIs, die Task<bool>
zurückgeben. Einige von ihnen sind jedoch zu verwenden, wenn ein NSError
Teil der Signatur war, d. h. die bool
war bereits true
und Sie mussten eine Ausnahme abfangen, um die NSError
zu erhalten.
Da einige Fehler sehr häufig sind und der Rückgabewert nicht nützlich war, wurde dieses Muster in unified geändert, um einen Task<Tuple<Boolean,NSError>>
zurückzugeben. Dadurch können Sie sowohl den Erfolg als auch alle Fehler überprüfen, die während des asynchronen Aufrufs aufgetreten sein könnten.
NSString im Vergleich zu Zeichenfolge
In einigen Fällen mussten einige Konstanten von string
in NSString
geändert werden, z. UITableViewCell
Klassisch
public virtual string ReuseIdentifier { get; }
Einheitlich
public virtual NSString ReuseIdentifier { get; }
Im Allgemeinen bevorzugen wir den .NET-Typ System.String
. Trotz der Apple-Richtlinien vergleichen einige native API konstante Zeiger (nicht die Zeichenfolge selbst), und dies kann nur funktionieren, wenn wir die Konstanten als NSString
verfügbar machen.
Objective-C Protokolle
Die ursprüngliche MonoTouch hatte keine vollständige Unterstützung für ObjC-Protokolle, und einige, nicht optimale API wurden hinzugefügt, um das häufigste Szenario zu unterstützen. Diese Einschränkung ist nicht mehr vorhanden, aber aus Gründen der Abwärtskompatibilität werden mehrere APIs in monotouch.dll
und XamMac.dll
beibehalten.
Diese Einschränkungen wurden entfernt und für die einheitlichen APIs bereinigt. Die meisten Änderungen sehen wie folgt aus:
Klassisch
public virtual AVAssetResourceLoaderDelegate Delegate { get; }
Einheitlich
public virtual IAVAssetResourceLoaderDelegate Delegate { get; }
Das I
Präfix bedeutet einheitliches Verfügbarmachen einer Schnittstelle anstelle eines bestimmten Typs für das ObjC-Protokoll. Dies erleichtert Fälle, in denen Sie den von Xamarin.iOS bereitgestellten typ nicht unterklassieren möchten.
Außerdem konnte einige API präziser und einfacher zu verwenden sein, z. B.:
Klassisch
public virtual void SelectionDidChange (NSObject uiTextInput);
Einheitlich
public virtual void SelectionDidChange (IUITextInput uiTextInput);
Eine solche API ist jetzt einfacher für uns, ohne sich auf die Dokumentation zu beziehen, und Ihre IDE-Code-Vervollständigung bietet Ihnen nützlichere Vorschläge basierend auf dem Protokoll/der Schnittstelle.
NSCoding Protocol
Unsere ursprüngliche Bindung enthielt eine .ctor(NSCoder) für jeden Typ – auch wenn das NSCoding
Protokoll nicht unterstützt wurde. In der NSObject
war eine einzelne Encode(NSCoder)
Methode vorhanden, um das Objekt zu codieren.
Diese Methode funktioniert jedoch nur, wenn die instance dem NSCoding-Protokoll entsprechen.
In der einheitlichen API haben wir dies behoben. Die neuen Assemblys verfügen nur über den .ctor(NSCoder)
, wenn der Typ entspricht NSCoding
. Auch solche Typen verfügen jetzt über eine Encode(NSCoder)
Methode, die der INSCoding
Schnittstelle entspricht.
Geringe Auswirkung: In den meisten Fällen wirkt sich diese Änderung nicht auf Anwendungen aus, da die alten, entfernten Konstruktoren nicht verwendet werden konnten.
Weitere Tipps
Weitere Zu beachtende Änderungen sind in den Tipps zum Aktualisieren von Apps auf die Einheitliche API aufgeführt.