Jak działa rozszerzenie Xamarin.Mac

W większości przypadków deweloper nigdy nie będzie musiał martwić się o wewnętrzną "magię" platformy Xamarin.Mac, jednak mając przybliżoną wiedzę na temat sposobu działania elementów pod maską, pomoże w interpretowaniu istniejącej dokumentacji przy użyciu obiektywu języka C# i problemów z debugowaniem, gdy wystąpią.

Na platformie Xamarin.Mac aplikacja łączy dwa światy: istnieje Objective-C środowisko uruchomieniowe oparte na wystąpieniach klas natywnych (NSString, NSApplicationitp.) i istnieje środowisko uruchomieniowe języka C# zawierające wystąpienia klas zarządzanych (System.String, HttpClientitp.). Między tymi dwoma światami platforma Xamarin.Mac tworzy dwukierunkowy mostek, dzięki czemu aplikacja może wywoływać metody (selektory) w Objective-C (np NSApplication.Init. ) i Objective-C wywoływać metody języka C# aplikacji z powrotem (na przykład metody na delegatze aplikacji). Ogólnie rzecz biorąc, wywołania są Objective-C obsługiwane w sposób niewidoczny za pośrednictwem wywołań P/Invoke, a niektóre kod środowiska uruchomieniowego Xamarin zapewnia.

Uwidacznianie klas/metod w języku C# do Objective-C

Jednak aby Objective-C wywołać z powrotem do obiektów języka C# aplikacji, muszą one być uwidocznione w sposób, który Objective-C może być zrozumiały. Odbywa się to za pomocą atrybutów Register i Export . Spójrz na następujący przykład:

[Register ("MyClass")]
public class MyClass : NSObject
{
   [Export ("init")]
   public MyClass ()
   {
   }

   [Export ("run")]
   public void Run ()
   {
   }
}

W tym przykładzie Objective-C środowisko uruchomieniowe będzie teraz wiedzieć o klasie o nazwie z selektorami o nazwie MyClassinit i run.

W większości przypadków jest to szczegóły implementacji, którą deweloper może zignorować, ponieważ większość wywołań zwrotnych odbieranych przez aplikację będzie albo za pośrednictwem metod przesłoniętych w base klasach (takich jak AppDelegate, Delegates), DataSourceslub w przypadku akcji przekazanych do interfejsów API. We wszystkich tych przypadkach Export atrybuty nie są niezbędne w kodzie języka C#.

Uruchamianie konstruktora

W wielu przypadkach deweloper musi uwidocznić interfejs API budowy klas języka C# aplikacji w Objective-C środowisku uruchomieniowym, aby można było utworzyć wystąpienie z miejsc, takich jak wywołanie w plikach Storyboard lub XIB. Poniżej przedstawiono pięć najczęściej używanych konstruktorów w aplikacjach platformy Xamarin.Mac:

// Called when created from unmanaged code
public CustomView (IntPtr handle) : base (handle)
{
   Initialize ();
}

// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public CustomView (NSCoder coder) : base (coder)
{
   Initialize ();
}

// Called from C# to instance NSView with a Frame (initWithFrame)
public CustomView (CGRect frame) : base (frame)
{
}

// Called from C# to instance NSView without setting the frame (init)
public CustomView () : base ()
{
}

// This is a special case constructor that you call on a derived class when the derived called has an [Export] constructor.
// For example, if you call init on NSString then you don’t want to call init on NSObject.
public CustomView () : base (NSObjectFlag.Empty)
{
}

Ogólnie rzecz biorąc, deweloper powinien pozostawić IntPtr konstruktory i NSCoder , które są generowane podczas tworzenia niektórych typów, takich jak sam niestandardowy NSViews . Jeśli platforma Xamarin.Mac musi wywołać jeden z tych konstruktorów w odpowiedzi na Objective-C żądanie środowiska uruchomieniowego i usunięto go, aplikacja ulegnie awarii wewnątrz kodu natywnego i może być trudna do rozwiązania dokładnie tego problemu.

Zarządzanie pamięcią i cykle

Zarządzanie pamięcią na platformie Xamarin.Mac jest na wiele sposobów bardzo podobne do platformy Xamarin.iOS. Jest to również złożony temat, który wykracza poza zakres tego dokumentu. Przeczytaj najlepsze rozwiązania dotyczące pamięci i wydajności.

Kompilacja z wyprzedzeniem

Zazwyczaj aplikacje platformy .NET nie kompilują się do kodu maszynowego podczas kompilowania, zamiast tego kompilują się w warstwie pośredniej o nazwie kod IL, który pobiera kod just-in-time (JIT) skompilowany do kodu maszynowego po uruchomieniu aplikacji.

Czas potrzebny środowisku uruchomieniowemu mono do skompilowania JIT tego kodu maszynowego może spowolnić uruchamianie aplikacji Xamarin.Mac o maksymalnie 20%, ponieważ wymaga to czasu na wygenerowanie niezbędnego kodu komputera.

Ze względu na ograniczenia nałożone przez firmę Apple w systemie iOS kompilacja JIT kodu IL nie jest dostępna dla platformy Xamarin.iOS. W związku z tym wszystkie aplikacje platformy Xamarin.iOS są pełne przed upływem czasu (AOT) skompilowane do kodu maszynowego podczas cyklu kompilacji.

Nowością dla platformy Xamarin.Mac jest możliwość AOT kodu IL podczas cyklu kompilacji aplikacji, podobnie jak w przypadku platformy Xamarin.iOS. Platforma Xamarin.Mac używa podejścia hybrydowego AOT, które kompiluje większość wymaganego kodu maszynowego, ale umożliwia środowisku uruchomieniowemu kompilowanie potrzebnych trampolin i elastyczność, aby nadal obsługiwać Emocje ion. Emituj (i inne przypadki użycia, które obecnie działają na platformie Xamarin.Mac).

Istnieją dwa główne obszary, w których usługa AOT może pomóc aplikacji Xamarin.Mac:

  • Lepsze "natywne" dzienniki awarii — jeśli aplikacja platformy Xamarin.Mac ulegnie awarii w kodzie natywnym, co jest typowym wystąpieniem podczas wykonywania nieprawidłowych wywołań do interfejsów API cocoa (takich jak wysyłanie null do metody, która jej nie akceptuje), natywne dzienniki awarii z ramkami JIT są trudne do przeanalizowania. Ponieważ ramki JIT nie zawierają informacji o debugowaniu, będzie wiele wierszy z przesunięciami szesnastkowymi i nie ma pojęcia, co się dzieje. Funkcja AOT generuje "prawdziwe" nazwane ramki, a ślady są znacznie łatwiejsze do odczytania. Oznacza to również, że aplikacja Xamarin.Mac będzie lepiej współdziałać z narzędziami natywnymi, takimi jak lldb i Instruments.
  • Lepsza wydajność czasu uruchamiania — w przypadku dużych aplikacji platformy Xamarin.Mac kompilowanie całego kodu w trybie JIT może zająć dużo czasu. Usługa AOT wykonuje tę pracę z góry.

Włączanie kompilacji AOT

Funkcja AOT jest włączona na platformie Xamarin.Mac, klikając dwukrotnie nazwę projektu w Eksplorator rozwiązań, przechodząc do pozycji Kompilacja dla komputerów Mac i dodając --aot:[options] do pola Dodatkowe argumenty mmp: (gdzie [options] jest co najmniej jedną opcją kontrolowania typu AOT, zobacz poniżej). Na przykład:

Adding AOT to additional mmp arguments

Ważne

Włączenie kompilacji AOT znacznie zwiększa czas kompilacji, czasami nawet kilka minut, ale może poprawić czas uruchamiania aplikacji średnio o 20%. W związku z tym kompilacja AOT powinna być włączona tylko w przypadku kompilacji wydania aplikacji platformy Xamarin.Mac.

Opcje kompilacji Aot

Istnieje kilka różnych opcji, które można dostosować podczas włączania kompilacji AOT w aplikacji Xamarin.Mac:

  • none - Brak kompilacji AOT. Ustawienie domyślne.
  • all - AOT kompiluje każdy zestaw w monoBundle.
  • core— Funkcja AOT kompiluje Xamarin.MacSystem zestawy i mscorlib .
  • sdk — Funkcja AOT kompiluje Xamarin.Mac zestawy bibliotek klas bazowych (BCL).
  • |hybrid — Dodanie tej opcji do jednej z powyższych opcji umożliwia użycie hybrydowej funkcji AOT, która umożliwia usuwanie nazw IL, ale spowoduje dłuższy czas kompilacji.
  • + — Zawiera pojedynczy plik kompilacji AOT.
  • - — Usuwa pojedynczy plik z kompilacji AOT.

Na przykład --aot:all,-MyAssembly.dll włączenie kompilacji AOT we wszystkich zestawach w elemecie MonoBundle z wyjątkiemMyAssembly.dll włączenia --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll hybrydowego kodu AOT obejmuje MyOtherAssembly.dll element i z wyłączeniem elementu mscorlib.dll.

Częściowe statyczne registrar

Podczas tworzenia aplikacji platformy Xamarin.Mac zminimalizowanie czasu między ukończeniem zmiany a testowaniem może być ważne, aby sprostać terminom programowania. Strategie, takie jak modularyzacja baz kodu i testów jednostkowych, mogą pomóc skrócić czas kompilacji, ponieważ zmniejszają liczbę przypadków, w których aplikacja będzie wymagała kosztownej pełnej kompilacji.

Ponadto i nowe wersje dla platformy Xamarin.Mac, Partial Static Registrar (pionierskie przez platformę Xamarin.iOS) mogą znacznie skrócić czas uruchamiania aplikacji Xamarin.Mac w konfiguracji debugowania . Zrozumienie, w jaki sposób użycie funkcji Partial Static Registrar może wycisnąć prawie 5-krotne ulepszenie uruchamiania debugowania, zajmie trochę tła, registrar co to jest, jaka jest różnica między statyczną i dynamiczną, a co robi ta "częściowa wersja statyczna".

Informacje o registrar

Pod maską dowolnej aplikacji platformy Xamarin.Mac leży struktura Cocoa firmy Apple i Objective-C środowiska uruchomieniowego. Tworzenie mostu między tym "natywnym światem" a "zarządzanym światem" języka C# jest główną odpowiedzialnością platformy Xamarin.Mac. Część tego zadania jest obsługiwana przez metodę registrar, która jest wykonywana wewnątrz NSApplication.Init () metody . Jest to jeden z powodów, dla których należy najpierw wywołać dowolne użycie interfejsów API platformy Cocoa na platformie Xamarin.Mac NSApplication.Init .

Zadaniem registrarjest informowanie Objective-C środowiska uruchomieniowego o istnieniu klas języka C# aplikacji, które pochodzą z klas, takich jak NSApplicationDelegate, , NSViewNSWindowi NSObject. Wymaga to skanowania wszystkich typów w aplikacji w celu określenia, jakie elementy wymagają zarejestrowania i jakich elementów każdego typu należy zgłosić.

To skanowanie można wykonać dynamicznie, podczas uruchamiania aplikacji z odbiciem lub statycznie jako krok czasu kompilacji. Podczas wybierania typu rejestracji deweloper powinien pamiętać o następujących kwestiach:

  • Rejestracja statyczna może znacząco skrócić czas uruchamiania, ale może znacznie spowolnić czasy kompilacji (zazwyczaj więcej niż dwukrotnie czas kompilacji debugowania). Będzie to wartość domyślna dla kompilacji konfiguracji wydania .
  • Rejestracja dynamiczna opóźnia tę pracę do momentu uruchomienia aplikacji i pominięcia generowania kodu, ale ta dodatkowa praca może spowodować zauważalne wstrzymanie (co najmniej dwie sekundy) podczas uruchamiania aplikacji. Jest to szczególnie zauważalne w kompilacjach konfiguracji debugowania, które domyślnie jest rejestracją dynamiczną i których odbicie jest wolniejsze.

Częściowa rejestracja statyczna, po raz pierwszy wprowadzona w środowisku Xamarin.iOS 8.13, daje deweloperowi najlepsze z obu opcji. Dzięki wstępnemu obliczeniu informacji rejestracyjnych każdego elementu i Xamarin.Mac.dll wysłaniu tych informacji za pomocą platformy Xamarin.Mac w bibliotece statycznej (która musi być połączona tylko z elementem w czasie kompilacji), firma Microsoft usunęła większość czasu odbicia dynamicznego registrar , nie wpływając jednocześnie na czas kompilacji.

Włączanie częściowej statycznej registrar

Funkcja Partial Static Registrar jest włączona na platformie Xamarin.Mac, klikając dwukrotnie nazwę projektu w Eksplorator rozwiązań, przechodząc do obszaru Kompilacja dla komputerów Mac i dodając --registrar:static do pola Dodatkowe argumenty mmp: . Na przykład:

Adding the partial static registrar to additional mmp arguments

Dodatkowe zasoby

Poniżej przedstawiono bardziej szczegółowe wyjaśnienia dotyczące sposobu działania elementów wewnętrznie: