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
, , NSApplication
dll) dan ada runtime C# yang berisi instans kelas terkelola (System.String
, , HttpClient
dll). 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
, , DataSources
Delegates
) 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:
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 mengkompilasiXamarin.Mac
,System
danmscorlib
rakitan.sdk
- AOT mengkompilasiXamarin.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
, , NSView
NSWindow
, 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:
Sumber Daya Tambahan:
Berikut adalah beberapa penjelasan yang lebih rinci tentang bagaimana hal-hal bekerja secara internal: