Bagikan melalui


Objective-C pemilih di Xamarin.iOS

Bahasa Objective-C didasarkan pada pemilih. Pemilih adalah pesan yang dapat dikirim ke objek atau kelas. Xamarin.iOS memetakan pemilih instans ke metode instans, dan pemilih kelas ke metode statis.

Tidak seperti fungsi C normal (dan seperti fungsi anggota C++), Anda tidak dapat langsung memanggil pemilih menggunakan P/Invoke Sebagai gantinya, pemilih dikirim ke Objective-C kelas atau instans menggunakan objc_msgSend Fungsi.

Untuk informasi selengkapnya tentang pesan di Objective-C, lihat panduan Bekerja dengan Objek Apple.

Contoh

Misalkan Anda ingin memanggil sizeWithFont:forWidth:lineBreakMode: pemilih pada NSString. Deklarasi (dari dokumentasi Apple) adalah:

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

API ini memiliki karakteristik berikut:

  • Jenis pengembalian adalah CGSize untuk API Terpadu.
  • Parameter font adalah UIFont (dan jenis (tidak langsung) yang berasal dari NSObject, dan dipetakan ke System.IntPtr.
  • Parameter width , CGFloat, dipetakan ke nfloat.
  • Parameter lineBreakMode , UILineBreakMode, telah terikat di Xamarin.iOS sebagai UILineBreakMode Enumerasi.

Menyatukan semuanya, objc_msgSend deklarasi harus cocok:

CGSize objc_msgSend(
    IntPtr target,
    IntPtr selector,
    IntPtr font,
    nfloat width,
    UILineBreakMode mode
);

Deklarasikan sebagai berikut:

[DllImport (Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend")]
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int (
    IntPtr target,
    IntPtr selector,
    IntPtr font,
    nfloat width,
    UILineBreakMode mode
);

Untuk memanggil metode ini, gunakan kode seperti berikut:

NSString target = ...
Selector selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = ...
nfloat width = ...
UILineBreakMode mode = ...

CGSize size = cgsize_objc_msgSend_IntPtr_float_int(
    target.Handle,
    selector.Handle,
    font == null ? IntPtr.Zero : font.Handle,
    width,
    mode
);

Jika nilai yang dikembalikan adalah struktur yang berukuran kurang dari 8 byte (seperti yang lebih SizeF lama digunakan sebelum beralih ke API Terpadu), kode di atas akan berjalan pada simulator tetapi mengalami crash pada perangkat. Untuk memanggil pemilih yang mengembalikan nilai berukuran kurang dari 8 bit, nyatakan objc_msgSend_stret fungsi:

[DllImport (MonoTouch.Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend_stret")]
static extern void cgsize_objc_msgSend_stret_IntPtr_float_int (
    out CGSize retval,
    IntPtr target,
    IntPtr selector,
    IntPtr font,
    nfloat width,
    UILineBreakMode mode
);

Untuk memanggil metode ini, gunakan kode seperti berikut:

NSString      target = ...
Selector    selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont          font = ...
nfloat          width = ...
UILineBreakMode mode = ...

CGSize size;

if (Runtime.Arch == Arch.SIMULATOR)
    size = cgsize_objc_msgSend_IntPtr_float_int(
        target.Handle,
        selector.Handle,
        font == null ? IntPtr.Zero : font.Handle,
        width,
        mode
    );
else
    cgsize_objc_msgSend_stret_IntPtr_float_int(
        out size,
        target.Handle, selector.Handle,
        font == null ? IntPtr.Zero: font.Handle,
        width,
        mode
    );

Memanggil pemilih

Memanggil pemilih memiliki tiga langkah:

  1. Dapatkan target pemilih.
  2. Dapatkan nama pemilih.
  3. Panggil objc_msgSend dengan argumen yang sesuai.

Target pemilih

Target pemilih adalah instans objek atau Objective-C kelas. Jika target adalah instans dan berasal dari jenis Xamarin.iOS terikat, gunakan ObjCRuntime.INativeObject.Handle properti .

Jika target adalah kelas, gunakan ObjCRuntime.Class untuk mendapatkan referensi ke instans kelas, lalu gunakan Class.Handle properti .

Nama pemilih

Nama pemilih tercantum dalam dokumentasi Apple. Misalnya, NSString termasuk dan sizeWithFont:forWidth:lineBreakMode: pemilihsizeWithFont:. Titik dua yang disematkan dan di belakang adalah bagian dari nama pemilih dan tidak dapat dihilangkan.

Setelah Anda memiliki nama pemilih, Anda dapat membuat ObjCRuntime.Selector instans untuk itu.

Memanggil objc_msgSend

objc_msgSend mengirim pesan (pemilih) ke objek. Keluarga fungsi ini mengambil setidaknya dua argumen yang diperlukan: target pemilih (instans atau handel kelas), pemilih itu sendiri, dan argumen apa pun yang diperlukan untuk pemilih. Argumen instans dan pemilih harus System.IntPtr, dan semua argumen yang tersisa harus cocok dengan jenis yang nint diharapkan pemilih, misalnya untuk int, atau System.IntPtr untuk semua NSObjectjenis turunan. Gunakan NSObject.Handle properti untuk mendapatkan IntPtr instans Objective-C jenis.

Ada lebih dari satu objc_msgSend fungsi:

  • Gunakan objc_msgSend_stret untuk pemilih yang mengembalikan struct. Pada ARM, ini mencakup semua jenis pengembalian yang bukan enumerasi atau salah satu jenis bawaan C (char, , short, intlong, float, double). Pada x86 (simulator), metode ini perlu digunakan untuk semua struktur yang berukuran lebih dari 8 byte (CGSize adalah 8 byte dan tidak digunakan objc_msgSend_stret dalam simulator).
  • Gunakan objc_msgSend_fpret untuk pemilih yang mengembalikan nilai titik mengambang pada x86 saja. Fungsi ini tidak perlu digunakan pada ARM; sebagai gantinya, gunakan objc_msgSend.
  • Fungsi objc_msgSend utama digunakan untuk semua pemilih lainnya.

Setelah Anda memutuskan fungsi mana yang objc_msgSend perlu Anda panggil (simulator dan perangkat masing-masing mungkin memerlukan metode yang berbeda), Anda dapat menggunakan metode normal [DllImport] untuk mendeklarasikan fungsi untuk pemanggilan nanti.

Serangkaian deklarasi yang telah dibuat objc_msgSend sebelumnya dapat ditemukan di ObjCRuntime.Messaging.

Pemanggilan yang berbeda pada simulator dan perangkat

Seperti yang dijelaskan di atas, Objective-C memiliki tiga jenis objc_msgSend metode: satu untuk pemanggilan reguler, satu untuk pemanggilan yang mengembalikan nilai titik mengambang (hanya x86), dan satu untuk pemanggilan yang mengembalikan nilai struktur. Yang terakhir termasuk akhiran _stret dalam ObjCRuntime.Messaging.

Jika Anda memanggil metode yang akan mengembalikan struct tertentu (aturan yang dijelaskan di bawah), Anda harus memanggil metode dengan nilai yang dikembalikan sebagai parameter pertama sebagai out nilai:

// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);

Aturan kapan menggunakan _stret_ metode berbeda pada x86 dan ARM. Jika Anda ingin pengikatan Anda berfungsi pada simulator dan perangkat, tambahkan kode seperti berikut:

if (Runtime.Arch == Arch.DEVICE)
{
    PointF ret;
    Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, myHandle, selector.Handle);
    return ret;
}
else
{
    return Messaging.PointF_objc_msgSend_PointF_IntPtr (myHandle, selector.Handle);
}

Menggunakan metode objc_msgSend_stret

Saat membangun ARM, gunakan objc_msgSend_stretuntuk jenis nilai apa pun yang bukan enumerasi atau salah satu jenis dasar untuk enumerasi (int, , byte, shortlong, double, float).

Saat membangun untuk x86, gunakan objc_msgSend_stretuntuk jenis nilai apa pun yang bukan enumerasi atau salah satu jenis dasar untuk enumerasi (int, , byte, shortlong, double, float) dan yang ukuran aslinya lebih besar dari 8 byte.

Membuat tanda tangan Anda sendiri

Inti berikut dapat digunakan untuk membuat tanda tangan Anda sendiri, jika diperlukan.