Bagikan melalui


Cara kerja Xamarin.Mac

Sebagian besar waktu pengembang tidak perlu khawatir tentang "sihir" internal Xamarin.Mac, namun, memiliki pemahaman kasar tentang bagaimana hal-hal bekerja di bawah tenda akan membantu dalam menafsirkan dokumentasi yang ada dengan lensa C# dan masalah debugging ketika mereka muncul.

Di Xamarin.Mac, aplikasi menjembatani dua dunia: Ada Objective-C runtime berbasis yang berisi instans kelas asli (NSString, , NSApplicationdll) dan ada runtime C# yang berisi instans kelas terkelola (System.String, , HttpClientdll). Di antara kedua dunia ini, Xamarin.Mac membuat jembatan dua arah sehingga aplikasi dapat memanggil metode (pemilih) di Objective-C (seperti NSApplication.Init) dan Objective-C dapat memanggil kembali metode C# aplikasi (seperti metode pada delegasi aplikasi). Secara umum, panggilan ke dalam Objective-C ditangani secara transparan melalui P/Invokes dan beberapa kode runtime yang disediakan Xamarin.

Mengekspos kelas / metode C# ke Objective-C

Namun, untuk Objective-C memanggil kembali objek C# aplikasi, mereka perlu diekspos dengan cara yang Objective-C dapat memahami. Ini dilakukan melalui Register atribut dan Export . Ambil contoh berikut:

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

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

Dalam contoh ini, Objective-C runtime sekarang akan tahu tentang kelas yang disebut MyClass dengan pemilih yang disebut init dan run.

Dalam kebanyakan kasus, ini adalah detail implementasi yang dapat diabaikan pengembang, karena sebagian besar panggilan balik yang diterima aplikasi akan melalui metode yang ditimpa pada base kelas (seperti AppDelegate, , DataSourcesDelegates) atau pada Tindakan yang diteruskan ke API. Dalam semua kasus tersebut, Export atribut tidak diperlukan dalam kode C#.

Runthrough konstruktor

Dalam banyak kasus, pengembang harus mengekspos API konstruksi kelas C# aplikasi ke Objective-C runtime sehingga dapat dibuat dari tempat-tempat seperti ketika dipanggil dalam file Storyboard atau XIB. Berikut adalah lima konstruktor paling umum yang digunakan dalam aplikasi 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)
{
}

Secara umum, pengembang harus meninggalkan IntPtr konstruktor dan NSCoder yang dihasilkan saat membuat beberapa jenis seperti kustom NSViews saja. Jika Xamarin.Mac perlu memanggil salah satu konstruktor ini sebagai respons terhadap Objective-C permintaan runtime dan Anda telah menghapusnya, aplikasi akan crash di dalam kode asli dan mungkin sulit untuk mencari tahu persis masalahnya.

Manajemen dan siklus memori

Manajemen memori di Xamarin.Mac dalam banyak hal sangat mirip dengan Xamarin.iOS. Ini juga merupakan topik yang kompleks, satu di luar cakupan dokumen ini. Silakan baca Praktik Terbaik Memori dan Performa.

Kompilasi sebelumnya

Biasanya, aplikasi .NET tidak dikompilasi ke kode mesin saat dibuat, sebagai gantinya mereka mengkompilasi ke lapisan perantara yang disebut kode IL yang mendapatkan Just-In-Time (JIT) yang dikompilasi ke kode mesin saat aplikasi diluncurkan.

Waktu yang dibutuhkan runtime mono ke JIT mengkompilasi kode mesin ini dapat memperlambat peluncuran aplikasi Xamarin.Mac hingga 20%, karena membutuhkan waktu agar kode mesin yang diperlukan dihasilkan.

Karena keterbatasan yang diberlakukan oleh Apple di iOS, kompilasi JIT dari kode IL tidak tersedia untuk Xamarin.iOS. Akibatnya, semua aplikasi Xamarin.iOS dilengkapi dengan Ahead-Of-Time (AOT) penuh yang dikompilasi ke kode mesin selama siklus build.

Baru menggunakan Xamarin.Mac adalah kemampuan untuk AOT kode IL selama siklus build aplikasi, seperti yang dapat dilakukan Xamarin.iOS. Xamarin.Mac menggunakan pendekatan Hybrid AOT yang mengkompilasi sebagian besar kode mesin yang diperlukan, tetapi memungkinkan runtime untuk mengkompilasi trampoline yang diperlukan dan fleksibilitas untuk terus mendukung Reflection.Emit (dan kasus penggunaan lainnya yang saat ini bekerja di Xamarin.Mac).

Ada dua area utama di mana AOT dapat membantu aplikasi Xamarin.Mac:

  • Log crash "asli" yang lebih baik - Jika aplikasi Xamarin.Mac mengalami crash dalam kode asli, yang merupakan kejadian umum saat melakukan panggilan yang tidak valid ke API Kakao (seperti mengirim null ke dalam metode yang tidak menerimanya), log crash asli dengan bingkai JIT sulit dianalisis. Karena bingkai JIT tidak memiliki informasi debug, akan ada beberapa baris dengan offset hex dan tidak ada petunjuk apa yang terjadi. AOT menghasilkan bingkai bernama "nyata" dan jejaknya jauh lebih mudah dibaca. Ini juga berarti aplikasi Xamarin.Mac akan berinteraksi lebih baik dengan alat asli seperti lldb dan Instruments.
  • Performa waktu peluncuran yang lebih baik - Untuk aplikasi Xamarin.Mac besar, dengan waktu mulai beberapa detik, JIT yang mengkompilasi semua kode dapat memakan waktu yang signifikan. AOT melakukan pekerjaan ini di muka.

Mengaktifkan kompilasi AOT

AOT diaktifkan di Xamarin.Mac dengan mengklik ganda Nama Proyek di Penjelajah Solusi, menavigasi ke Mac Build dan menambahkan --aot:[options] ke bidang Argumen mmp tambahan: (di mana [options] adalah satu atau beberapa opsi untuk mengontrol jenis AOT, lihat di bawah). Contohnya:

Adding AOT to additional mmp arguments

Penting

Mengaktifkan kompilasi AOT secara dramatis meningkatkan waktu build, terkadang hingga beberapa menit, tetapi dapat meningkatkan waktu peluncuran aplikasi rata-rata 20%. Akibatnya, kompilasi AOT hanya boleh diaktifkan pada Rilis build aplikasi Xamarin.Mac.

Opsi kompilasi aot

Ada beberapa opsi berbeda yang dapat disesuaikan saat mengaktifkan kompilasi AOT pada aplikasi Xamarin.Mac:

  • none - Tidak ada kompilasi AOT. Ini adalah pengaturan default.
  • all - AOT mengkompilasi setiap rakitan di MonoBundle.
  • core - AOT mengkompilasi Xamarin.Mac, System dan mscorlib rakitan.
  • sdk - AOT mengkompilasi Xamarin.Mac rakitan dan Pustaka Kelas Dasar (BCL).
  • |hybrid - Menambahkan ini ke salah satu opsi di atas memungkinkan AOT hibrid yang memungkinkan pengupasan IL, tetapi akan menghasilkan waktu kompilasi yang lebih lama.
  • + - Menyertakan satu file untuk kompilasi AOT.
  • - - Menghapus satu file dari kompilasi AOT.

Misalnya, --aot:all,-MyAssembly.dll akan mengaktifkan kompilasi AOT pada semua rakitan di MonoBundle kecualiMyAssembly.dll dan --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll akan mengaktifkan hibrid, kode AOT menyertakan MyOtherAssembly.dll dan mengecualikan mscorlib.dll.

Statis parsial registrar

Saat mengembangkan aplikasi Xamarin.Mac, meminimalkan waktu antara menyelesaikan perubahan dan pengujian, dapat menjadi penting untuk memenuhi tenggat waktu pengembangan. Strategi seperti modularisasi basis kode dan pengujian unit dapat membantu mengurangi waktu kompilasi, karena mengurangi berapa kali aplikasi akan memerlukan pembangunan ulang penuh yang mahal.

Selain itu, dan baru untuk Xamarin.Mac, StatisRegistrarParsial (sebagaimana dipelopori oleh Xamarin.iOS) dapat secara dramatis mengurangi waktu peluncuran aplikasi Xamarin.Mac dalam konfigurasi Debug. Memahami bagaimana menggunakan Statis Registrar Parsial dapat memencet peningkatan hampir 5x dalam peluncuran debug akan mengambil sedikit latar belakang tentang apa registrar itu, apa perbedaannya antara statis dan dinamis, dan apa yang dilakukan versi "statis parsial" ini.

Tentang registrar

Di bawah kap aplikasi Xamarin.Mac apa pun terletak kerangka kerja Kakao dari Apple dan Objective-C runtime. Membangun jembatan antara "dunia asli" ini dan "dunia terkelola" C# adalah tanggung jawab utama Xamarin.Mac. Bagian dari tugas ini ditangani oleh registrar, yang dijalankan di dalam NSApplication.Init () metode. Ini adalah salah satu alasan bahwa setiap penggunaan API Kakao di Xamarin.Mac harus NSApplication.Init dipanggil terlebih dahulu.

Tugasnya adalah menginformasikan Objective-C runtime keberadaan kelas C# aplikasi yang berasal dari kelas seperti NSApplicationDelegate, , NSViewNSWindow, dan NSObject.registrar Ini memerlukan pemindaian semua jenis dalam aplikasi untuk menentukan apa yang perlu didaftarkan dan elemen apa pada setiap jenis yang akan dilaporkan.

Pemindaian ini dapat dilakukan baik secara dinamis, saat memulai aplikasi dengan refleksi, atau secara statis, sebagai langkah waktu build. Saat memilih jenis pendaftaran, pengembang harus mengetahui hal-hal berikut:

  • Pendaftaran statis dapat secara drastis mengurangi waktu peluncuran, tetapi dapat memperlambat waktu build secara signifikan (biasanya lebih dari waktu build debug ganda). Ini akan menjadi default untuk build konfigurasi Rilis .
  • Pendaftaran dinamis menunda pekerjaan ini sampai peluncuran aplikasi dan melewati pembuatan kode, tetapi pekerjaan tambahan ini dapat membuat jeda yang nyata (setidaknya dua detik) dalam peluncuran aplikasi . Ini sangat terlihat dalam build konfigurasi debug, yang default ke pendaftaran dinamis dan yang refleksinya lebih lambat.

Pendaftaran Statis Parsial, pertama kali diperkenalkan di Xamarin.iOS 8.13, memberi pengembang yang terbaik dari kedua opsi. Dengan melakukan pra-komputasi informasi pendaftaran setiap elemen dalam Xamarin.Mac.dll dan mengirimkan informasi ini dengan Xamarin.Mac dalam pustaka statis (yang hanya perlu ditautkan pada waktu build), Microsoft telah menghapus sebagian besar waktu refleksi dinamis registrar sambil tidak memengaruhi waktu build.

Mengaktifkan statis parsial registrar

Statik Registrar Parsial diaktifkan di Xamarin.Mac dengan mengklik dua kali Nama Proyek di Penjelajah Solusi, menavigasi ke Mac Build dan menambahkan --registrar:static ke bidang Argumen mmp tambahan: . Contohnya:

Adding the partial static registrar to additional mmp arguments

Sumber Daya Tambahan:

Berikut adalah beberapa penjelasan yang lebih rinci tentang bagaimana hal-hal bekerja secara internal: