Ü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:

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 und XamMac.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 und Xamarin.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. oder MonoMac. 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.Int32definiert 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 nintnuint 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 interwarten, 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 intnint 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 IntPtrakzeptiert. 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 Actionentfernt. 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 NSActionwerden 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 NSErrorzu 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 NSStringgeä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 NSStringverfü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.dllbeibehalten.

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.