- 07/12/2017
- 4 読むべき分
-
-
d
d
c
a
-
Objective-C言語はセレクタに基づいています。 セレクタは、オブジェクトまたはクラスに送信できるamessageです。 Xamarin。iOSは、インスタンスselectorstoインスタンスメソッド、およびクラスセレクタを静的メソッドにマッ
通常のC関数(およびC++メンバー関数のような)とは異なり、代わりにp/Invokeを使用してセレクタを直接呼び出すことはできません。objc_msgSend
関数を使用してセレクタをObjective-Cクラスまたはインスタンスに送信します。
Objective-Cのメッセージの詳細については、AppleのObjectsguideでの作業を見てみましょう。
例
NSString
でsizeWithFont:forWidth:lineBreakMode:
セレクタを呼び出したいとします。宣言(Appleのドキュメントから)は次のとおりです:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
このAPIには、次の特性があります:
- 統合APIの戻り値の型は
CGSize
です。 font
パラメータはUIFont(およびNSObjectから派生した(間接的に)型であり、Systemにマップされます。IntPtr。width
パラメータaCGFloat
はnfloat
にマップされます。lineBreakMode
パラメーターであるUILineBreakMode
は、Xamarinで既にバインドされています。iosをUILineBreakMode
列挙体として使用します。
すべてをまとめると、objc_msgSend
宣言が一致する必要があります:
CGSize objc_msgSend( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
次のように宣言します:
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
関数を宣言します:
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
を使用してclassinstanceへの参照を取得し、Class.Handle
プロパティを使用します。
セレクタ名
セレクタ名はAppleのドキュメントに記載されています。 たとえば、NSString
にはsizeWithFont:
およびsizeWithFont:forWidth:lineBreakMode:
セレクタが含まれます。 埋め込まれたコロンと末尾のコロンはセレクタ名の一部であり、省略することはできません。
セレクタ名を取得したら、そのインスタンスのObjCRuntime.Selector
インスタンスを作成できます。
objc_msgsend
objc_msgSend
を呼び出すと、オブジェクトにメッセージ(セレクタ)が送信されます。 このファミリoffunctionsは、少なくとも二つの必須引数を取ります:セレクタターゲット(aninstanceまたはクラスハンドル)、セレクタ自体、およびセレクタに必要な任意のargumentsrequired。 インスタンス引数とセレクタ引数はSystem.IntPtr
でなければならず、残りのすべての引数は、int
の場合はnint
、NSObject
から派生したすべての型の場合はSystem.IntPtr
と一致する必要が Objective-C型インスタンスのIntPtr
を取得するには、NSObject.Handle
プロパティを使用します。
複数のobjc_msgSend
機能があります:
- 構造体を返すセレクタには
objc_msgSend_stret
を使用します。 ARMでは、これには列挙型でもCの組み込み型でもないすべてのreturntypesが含まれます(char
,short
,int
,long
,float
,double
). X86(シミュレータ)では、thismethodはサイズが8バイトを超えるすべての構造体に使用する必要があります(CGSize
は8バイトであり、thesimulatorではobjc_msgSend_stret
を使用しません)。 - x86でのみ浮動小数点値を返すセレクタには
objc_msgSend_fpret
を使用します。 この関数はARMで使用する必要はありません。objc_msgSend
を使用してください。 - mainobjc_msgsend関数は、他のすべてのセレクタに使用されます。
どのobjc_msgSend
関数を呼び出す必要があるかを決定したら(シミュレータとデバイスにはそれぞれ異なるメソッドが必要な場合があります)、通常のメソッドを使用して、後の呼び出しのために関数を宣言できます。
既製のobjc_msgSend
宣言のセットはObjCRuntime.Messaging
にあります。
シミュレータとデバイス上の異なる呼び出し
上記のように、Objective-Cには、通常の呼び出し、ポイント値を返す呼び出し(x86のみ)、およびstruct値を返す呼び出しの3種類のobjc_msgSend
メソッドがあります。 後者はObjCRuntime.Messaging
に接尾辞_stret
を含みます。
特定の構造体(以下に説明するrulesdescribed)を返すメソッドを呼び出す場合は、戻り値をfirstparameterとして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
, byte
, short
, long
, double
, float
)そして、そのネイティブサイズは8バイトよりも大きいです。
独自の署名の作成
必要に応じて、以下の要点を使用して独自の署名を作成することができます。