Objective-C Xamarin.iOS 中的選取器
語言Objective-C是以選取器為基礎。 選取器是可以傳送至物件或 類別的訊息。 Xamarin.iOS 會將實例選取器對應至實例方法,並將類別選取器對應至靜態方法。
不同於一般 C 函式(和 C++ 成員函式),您無法使用 P/Invoke 直接叫用選取器,選取器會使用 傳送至Objective-C類別或實例objc_msgSend
功能。
如需 中 Objective-C訊息的詳細資訊,請參閱Apple使用 物件 指南。
範例
假設您想要叫用 sizeWithFont:forWidth:lineBreakMode:
上的 NSString
選取器。
宣告(來自蘋果的檔案) 是:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
此 API 具有下列特性:
- 傳回類型適用於
CGSize
整合 API。 - 參數
font
是 UIFont (且間接衍生自 NSObject 的類型,且會對應至 System.IntPtr。 - 參數
width
是CGFloat
,會對應至nfloat
。 - 參數
lineBreakMode
,已在UILineBreakMode
Xamarin.iOS 中系結為UILineBreakMode
枚舉。
將所有專案放在一起, objc_msgSend
宣告應該相符:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
將它宣告如下:
[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
);
若要呼叫此方法,請使用下列程序代碼:
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
);
如果傳回的值是大小小於 8 個字節的結構(例如切換至整合 API 之前使用的舊 SizeF
版本),上述程式代碼會在模擬器上執行,但在裝置上當機。 若要呼叫傳回大小小於 8 位值的選取器,請宣告函 objc_msgSend_stret
式:
[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
);
若要呼叫此方法,請使用下列程序代碼:
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
);
叫用選取器
叫用選取器有三個步驟:
- 取得選取器目標。
- 取得選取器名稱。
- 使用適當的自變數呼叫
objc_msgSend
。
選取器目標
選取器目標為物件實例或 Objective-C 類別。 如果目標是實例,而且來自系結的 Xamarin.iOS 類型,請使用 ObjCRuntime.INativeObject.Handle
屬性。
如果目標是類別,請使用 ObjCRuntime.Class
來取得類別實例的參考,然後使用 Class.Handle
屬性。
選取器名稱
選取器名稱會列在 Apple 的檔案中。 例如, NSString
包含 sizeWithFont:
和 sizeWithFont:forWidth:lineBreakMode:
選取器。 內嵌和尾端冒號是選取器名稱的一部分,無法省略。
擁有選取器名稱之後,您可以為其建立 ObjCRuntime.Selector
實例。
呼叫objc_msgSend
objc_msgSend
將訊息 (選取器) 傳送至 物件。 這個函式系列至少接受兩個必要自變數:選取器目標(實例或類別句柄)、選取器本身,以及選取器所需的任何自變數。 實例和選取器自變數必須是 System.IntPtr
,而且所有剩餘的自變數都必須符合選取器所預期的類型,例如 nint
, int
或 System.IntPtr
所有 NSObject
衍生型別的 。 使用 NSObject.Handle
要取得 IntPtr
型別 Objective-C 實例的屬性。
有一個 objc_msgSend
以上的函式:
- 用於
objc_msgSend_stret
傳回結構的選取器。 在 ARM 上,這包括所有不是列舉型別的傳回型別,或任何 C 內建型別(char
、、、int
short
、long
、double
float
。 在 x86(模擬器)上,此方法必須用於大小大於 8 個字節的所有結構(CGSize
是 8 個字節,不適用於objc_msgSend_stret
模擬器)。 - 用於
objc_msgSend_fpret
只傳回 x86 上浮點值的選取器。 此函式不需要用於ARM;請改用objc_msgSend
。 - 主要 objc_msgSend 函式會用於所有其他選取器。
一旦您決定需要呼叫哪一 objc_msgSend
個函式(模擬器和裝置可能需要不同的方法),您可以使用一般 [DllImport]
方法來宣告函式以供稍後叫用。
您可以在 中找到ObjCRuntime.Messaging
一組預先建立objc_msgSend
的宣告。
模擬器和裝置上的不同調用
如上所述, Objective-C 有三種 objc_msgSend
方法:一種用於一般調用,一種用於傳回浮點值的調用(僅限 x86),另一種用於傳回結構值的調用。 後者在 中包含ObjCRuntime.Messaging
後綴_stret
。
如果您要叫用將傳回特定結構的方法(如下所述規則),您必須使用傳回值作為值的第一個 out
參數叫用 方法:
// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
何時使用 _stret_
方法的規則在 x86 和 ARM 上有所不同。
如果您想要讓系結同時在模擬器和裝置上運作,請新增程序代碼,如下所示:
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);
}
使用 objc_msgSend_stret方法
建置 ARM 時,請使用 objc_msgSend_stret
表示任何不是列舉型別的實值型別,或列舉型別的任何基底型別(int
、、byte
、、short
long
、 double
float
。
建置 x86 時,請使用 objc_msgSend_stret
對於不是列舉型別的任何實值型別,或是列舉型別的任何基底型別,int
double
float
byte
short
long
其原生大小大於8個字節。
建立您自己的簽章
如有需要,您可以使用下列 gist 來建立您自己的簽章。