Udostępnij za pośrednictwem


Ujednolicony interfejs API — omówienie

Ujednolicony interfejs API platformy Xamarin umożliwia udostępnianie kodu między komputerami Mac i iOS oraz obsługą aplikacji 32 i 64-bitowych przy użyciu tego samego pliku binarnego. Ujednolicony interfejs API jest domyślnie używany w nowych projektach platform Xamarin.iOS i Xamarin.Mac.

Ważne

Klasyczny interfejs API platformy Xamarin, który poprzedzał ujednolicony interfejs API, został przestarzały.

  • Ostatnia wersja platformy Xamarin.iOS do obsługi klasycznego interfejsu API (monotouch.dll) to Xamarin.iOS 9.10.
  • Platforma Xamarin.Mac nadal obsługuje klasyczny interfejs API, ale nie jest już aktualizowany. Ponieważ jest przestarzała, deweloperzy powinni przenieść swoje aplikacje do ujednoliconego interfejsu API.

Aktualizowanie klasycznych aplikacji opartych na interfejsie API

Postępuj zgodnie z odpowiednimi instrukcjami dotyczącymi platformy:

Porady dotyczące aktualizowania kodu na potrzeby ujednoliconego interfejsu API

Niezależnie od migrowanych aplikacji zapoznaj się z tymi wskazówkami , aby ułatwić pomyślną aktualizację do ujednoliconego interfejsu API.

Podział biblioteki

Od tego momentu nasze interfejsy API będą udostępniane na dwa sposoby:

  • Klasyczny interfejs API: ograniczony do 32-bitowych (tylko) i uwidoczniony w monotouch.dll zestawach i XamMac.dll .
  • Ujednolicony interfejs API: obsługa programowania w wersji 32 i 64-bitowej przy użyciu pojedynczego interfejsu API dostępnego Xamarin.iOS.dll w zestawach i Xamarin.Mac.dll .

Oznacza to, że w przypadku deweloperów w przedsiębiorstwie (nie przeznaczonych dla sklepu App Store) możesz nadal korzystać z istniejących klasycznych interfejsów API, ponieważ zachowamy je na zawsze lub możesz uaktualnić do nowych interfejsów API.

Zmiany przestrzeni nazw

Aby zmniejszyć problemy z udostępnianiem kodu między naszymi produktami dla komputerów Mac i iOS, zmieniamy przestrzenie nazw dla interfejsów API w produktach.

Usuwamy prefiks "MonoTouch" z naszego produktu dla systemu iOS i "MonoMac" z naszego produktu Mac na typach danych.

Ułatwia to udostępnianie kodu między platformami Mac i iOS bez uciekania się do kompilacji warunkowej i zmniejsza szum u góry plików kodu źródłowego.

  • Klasyczny interfejs API: przestrzenie nazw używają MonoTouch. lub MonoMac. prefiksu.
  • Ujednolicony interfejs API: brak prefiksu przestrzeni nazw

Ustawienia domyślne środowiska uruchomieniowego

Ujednolicony interfejs API domyślnie używa modułu odśmiecania pamięci SGen i systemu zliczania nowych odwołań do śledzenia własności obiektu. Ta sama funkcja została przekierowana do platformy Xamarin.Mac.

Rozwiązuje to szereg problemów, z którymi deweloperzy borykają się ze starym systemem, a także ułatwiają zarządzanie pamięcią.

Należy pamiętać, że istnieje możliwość włączenia polecenia New Refcount nawet dla klasycznego interfejsu API, ale ustawienie domyślne jest konserwatywne i nie wymaga od użytkowników wprowadzania żadnych zmian. Dzięki ujednoliconemu interfejsowi API skorzystaliśmy z okazji zmiany wartości domyślnej i udostępniliśmy deweloperom wszystkie ulepszenia w tym samym czasie, że refaktoryzują i ponownie przetestują swój kod.

Zmiany interfejsu API

Ujednolicony interfejs API usuwa przestarzałe metody i istnieje kilka wystąpień, w których w nazwach interfejsów API znajdowały się literówki, gdy były one powiązane z oryginalnymi przestrzeniami nazw MonoTouch i MonoMac w klasycznych interfejsach API. Te wystąpienia zostały poprawione w nowych ujednoliconych interfejsach API i należy je zaktualizować w składniku, aplikacjach dla systemów iOS i Mac. Oto lista najczęściej używanych elementów, na które można napotkać:

Nazwa klasycznej metody interfejsu API Ujednolicona nazwa metody interfejsu API
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

Pełną listę zmian podczas przełączania z wersji klasycznej do ujednoliconego interfejsu API można znaleźć w naszej dokumentacji różnic między interfejsami API klasycznymi (monotouch.dll) a Ujednoliconymi (Xamarin.iOS.dll).

Aktualizowanie do ujednoliconej

Kilka starych/uszkodzonych/przestarzałych interfejsów API w wersji klasycznej nie jest dostępnych w ujednoliconym interfejsie API. Przed rozpoczęciem uaktualniania (ręcznego lub zautomatyzowanego) można łatwiej naprawić CS0616 ostrzeżenia, ponieważ będziesz mieć komunikat atrybutu [Obsolete] (część ostrzeżenia), aby poprowadzić Cię do odpowiedniego interfejsu API.

Należy pamiętać, że publikujemy różnice klasycznych i ujednoliconych zmian interfejsu API, które mogą być używane przed aktualizacjami projektu lub po nim. Nadal naprawianie przestarzałych wywołań w wersji klasycznej często będzie oszczędność czasu (mniej odnośników dokumentacji).

Postępuj zgodnie z tymi instrukcjami, aby zaktualizować istniejące aplikacje systemu iOS lub aplikacje dla komputerów Mac do ujednoliconego interfejsu API. Przejrzyj pozostałą część tej strony i te porady , aby uzyskać dodatkowe informacje na temat migracji kodu.

NuGet

Pakiety NuGet, które wcześniej obsługiwały platformę Xamarin.iOS za pośrednictwem klasycznego interfejsu API, opublikowały swoje zestawy przy użyciu pseudonimu platformy Monotouch10 .

Ujednolicony interfejs API wprowadza nowy identyfikator platformy dla zgodnych pakietów — Xamarin.iOS10. Aby dodać obsługę tej platformy, należy zaktualizować istniejące pakiety NuGet, tworząc interfejs API Unified.

Ważne

Jeśli wystąpi błąd w formularzu "Błąd 3 Nie można dołączyć zarówno "monotouch.dll" jak i "Xamarin.iOS.dll" w tym samym projekcie platformy Xamarin.iOS — "Xamarin.iOS.dll" jest jawnie przywołyny. Podczas gdy element "monotouch.dll" jest przywołyany przez element "xxx, Version=0.0.000, Culture=neutral, PublicKeyToken=null" po przekonwertowaniu aplikacji na ujednolicone interfejsy API, zwykle wynika to z posiadania składnika lub pakietu NuGet w projekcie, który nie został zaktualizowany do ujednoliconego interfejsu API. Musisz usunąć istniejący składnik/NuGet, zaktualizować go do wersji obsługującej ujednolicone interfejsy API i wykonać czystą kompilację.

Droga do 64 bitów

Aby zapoznać się z informacjami na temat obsługi aplikacji 32-bitowych i 64-bitowych oraz informacji o strukturach, zobacz zagadnienia dotyczące platformy 32 i 64-bitowej.

Nowe typy danych

Na podstawie różnicy interfejsy API dla komputerów Mac i iOS używają typów danych specyficznych dla architektury, które są zawsze 32-bitowe na platformach 32-bitowych i 64-bitowych na platformach 64-bitowych.

Na przykład Objective-C mapuje NSInteger typ danych na int32_t w systemach 32-bitowych i int64_t na systemy 64-bitowe.

Aby dopasować to zachowanie, w naszym ujednoliconym interfejsie API zastępujemy poprzednie zastosowania int (które na platformie .NET są zdefiniowane jako zawsze System.Int32) na nowy typ danych: System.nint. Możesz traktować "n" jako "natywny", więc natywny typ liczby całkowitej platformy.

Wprowadzamy nintusługę , nuint a nfloat także udostępniamy typy danych oparte na nich w razie potrzeby.

Aby dowiedzieć się więcej na temat tych zmian typów danych, zobacz dokument Native Types (Typy natywne).

Jak wykryć architekturę aplikacji systemu iOS

Mogą wystąpić sytuacje, w których aplikacja musi wiedzieć, czy działa w 32-bitowym lub 64-bitowym systemie iOS. Do sprawdzenia architektury można użyć następującego kodu:

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

Tablice i System.Collections.Generic

Ponieważ indeksatory języka C# oczekują typu int, należy jawnie rzutować nint wartości, aby uzyskać dostęp do int elementów w kolekcji lub tablicy. Na przykład:

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

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

Jest to oczekiwane zachowanie, ponieważ rzutowanie z int do nint jest straty na 64 bity, niejawna konwersja nie jest wykonywana.

Konwertowanie daty/godziny na NSDate

W przypadku korzystania z ujednoliconych interfejsów API niejawna konwersja DateTime wartości NSDate nie jest już wykonywana. Te wartości będą musiały zostać jawnie przekonwertowane z jednego typu na inny. Następujące metody rozszerzenia mogą służyć do automatyzacji tego procesu:

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;
}

Przestarzałe interfejsy API i literówki

W klasycznym interfejsie API platformy Xamarin.iOS (monotouch.dll) [Obsolete] atrybut został użyty na dwa różne sposoby:

  • Przestarzały interfejs API systemu iOS: jest to, gdy firma Apple wskazuje, że przestanie używać interfejsu API, ponieważ jest zastępowany przez nowsze. Klasyczny interfejs API jest nadal w porządku i często wymagany (jeśli obsługujesz starszą wersję systemu iOS). Taki interfejs API (i [Obsolete] atrybut) są uwzględniane w nowych zestawach platformy Xamarin.iOS.
  • Niepoprawny interfejs API Niektórzy interfejs API mieli literówki w swoich nazwach.

W przypadku oryginalnych zestawów (monotouch.dll i XamMac.dll) zachowaliśmy stary kod dostępny pod kątem zgodności, ale zostały usunięte z zestawów ujednoliconego interfejsu API (Xamarin.iOS.dll i Xamarin.Mac)

Podklasy NSObject .ctor(IntPtr)

Każda NSObject podklasa ma konstruktor, który akceptuje element IntPtr. W ten sposób można utworzyć wystąpienie nowego wystąpienia zarządzanego z natywnego dojścia ObjC.

W wersji klasycznej public był to konstruktor. Jednak łatwo było niewłaściwego użycia tej funkcji w kodzie użytkownika, np. utworzenie kilku wystąpień zarządzanych dla pojedynczego wystąpienia objC lub utworzenie wystąpienia zarządzanego, które nie będzie miało oczekiwanego stanu zarządzanego (w przypadku podklas).

Aby uniknąć tego rodzaju problemów, IntPtr konstruktory są teraz protected w ujednoliconym interfejsie API, które mają być używane tylko do podklasy. Zapewni to, że prawidłowy/bezpieczny interfejs API jest używany do tworzenia wystąpienia zarządzanego na podstawie dojść, tj.

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

Ten interfejs API zwróci istniejące wystąpienie zarządzane (jeśli już istnieje) lub utworzy nowe (jeśli jest wymagane). Jest już dostępny w klasycznym i ujednoliconym interfejsie API.

Należy pamiętać, że .ctor(NSObjectFlag) element jest teraz również, protected ale ten był rzadko używany poza podklasą.

NSAction zastąpiona akcją

Dzięki ujednoliconym interfejsom NSAction API usunięto standardową platformę .NET Action. Jest to duża poprawa, ponieważ Action jest to typowy typ platformy .NET, natomiast NSAction był specyficzny dla platformy Xamarin.iOS. Obie robią dokładnie to samo, ale były one odrębne i niezgodne typy i spowodowały, że w celu uzyskania tego samego wyniku trzeba napisać więcej kodu.

Jeśli na przykład istniejąca aplikacja platformy Xamarin zawiera następujący kod:

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

Teraz można go zastąpić prostą lambdą:

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

Wcześniej był to błąd kompilatora, ponieważ Action nie można przypisać elementu do NSActionelementu , ale ponieważ UITapGestureRecognizer teraz Action zamiast elementu NSAction jest prawidłowy w ujednoliconych interfejsach API.

Delegaty niestandardowe zastąpione akcją<T>

W ujednoliconym kilku prostych (np. jeden parametr) delegatów platformy .net zostały zastąpione elementem Action<T>. Na przykład

public delegate void NSNotificationHandler (NSNotification notification);

można teraz używać jako .Action<NSNotification> To podwyższanie poziomu ponownego użycia kodu i zmniejszanie duplikacji kodu zarówno w środowisku Xamarin.iOS, jak i we własnych aplikacjach.

Wartość logiczna> zadania<została zastąpiona wartością logiczną zadania<, NSError>>

W wersji klasycznej wystąpiły pewne asynchroniczne interfejsy API zwracające Task<bool>element . Jednak niektóre z nich, gdzie mają być używane, gdy NSError element był częścią podpisu, tj. bool był już true i trzeba było złapać wyjątek, aby uzyskać NSError.

Ponieważ niektóre błędy są bardzo powszechne i wartość zwracana nie była przydatna, ten wzorzec został zmieniony w ujednolicony , aby zwrócić Task<Tuple<Boolean,NSError>>wartość . Dzięki temu można sprawdzić powodzenie i wszelkie błędy, które mogły wystąpić podczas wywołania asynchronicznego.

Ciąg NSString a ciąg

W kilku przypadkach niektóre stałe musiały zostać zmienione z string na NSString, np. UITableViewCell

Klasyczny

public virtual string ReuseIdentifier { get; }

Unified

public virtual NSString ReuseIdentifier { get; }

Ogólnie rzecz biorąc, preferujemy typ .NET System.String . Jednak pomimo wytycznych firmy Apple niektóre natywne interfejsy API porównują stałe wskaźniki (a nie sam ciąg) i może to działać tylko wtedy, gdy uwidaczniamy stałe jako NSString.

Objective-C Protokołów

Oryginalny interfejs MonoTouch nie miał pełnej obsługi protokołów ObjC, a niektóre, nie optymalne, interfejs API zostały dodane do obsługi najbardziej typowego scenariusza. To ograniczenie już nie istnieje, ale w celu zapewnienia zgodności z poprzednimi wersjami kilka interfejsów API jest przechowywanych wewnątrz monotouch.dll i XamMac.dll.

Te ograniczenia zostały usunięte i wyczyszczone w ujednoliconych interfejsach API. Większość zmian będzie wyglądać następująco:

Klasyczny

public virtual AVAssetResourceLoaderDelegate Delegate { get; }

Unified

public virtual IAVAssetResourceLoaderDelegate Delegate { get; }

Prefiks I oznacza ujednolicone uwidacznienie interfejsu zamiast określonego typu dla protokołu ObjC. Ułatwi to przypadki, w których nie chcesz podklasować określonego typu dostarczonego przez platformę Xamarin.iOS.

Ponadto niektóre interfejsy API mogą być bardziej precyzyjne i łatwe w użyciu, np.:

Klasyczny

public virtual void SelectionDidChange (NSObject uiTextInput);

Unified

public virtual void SelectionDidChange (IUITextInput uiTextInput);

Taki interfejs API jest teraz łatwiejszy, bez odwoływania się do dokumentacji, a uzupełnianie kodu IDE zapewni bardziej przydatne sugestie oparte na protokole/interfejsie.

Protokół NSCoding

Nasze oryginalne powiązanie obejmowało obiekt .ctor(NSCoder) dla każdego typu — nawet jeśli nie obsługuje NSCoding protokołu. Encode(NSCoder) Pojedyncza metoda była obecna w obiekcie NSObject w celu zakodowania obiektu. Jednak ta metoda działałaby tylko wtedy, gdy wystąpienie jest zgodne z protokołem NSCoding.

Rozwiązaliśmy ten problem w ujednoliconym interfejsie API. Nowe zestawy będą miały .ctor(NSCoder) wartość tylko wtedy, gdy typ jest NSCodingzgodny z . Ponadto takie typy mają teraz metodę zgodną Encode(NSCoder) z interfejsem INSCoding .

Niski wpływ: w większości przypadków ta zmiana nie wpłynie na aplikacje, ponieważ stare, usunięte konstruktory nie mogą być używane.

Dalsze Wskazówki

Dodatkowe zmiany, o których należy pamiętać, są wymienione w poradach dotyczących aktualizowania aplikacji do ujednoliconego interfejsu API.