- 07/12/2017
- 4 zápis ke čtení
-
-
d
-
d
-
c
-
a
-
jazyk Objective-C je založen na selektorech. Selektor je amessage, který lze odeslat do objektu nebo třídy. Xamarin.iOS maps instance selectorsto instance metody, a selektory tříd na statické metody.
na rozdíl od běžných funkcí C (a jako C++ členské funkce), nemůžete přímo vyvolat selektor pomocí p / Invoke místo toho jsou selektory odeslány do třídy Objective-C nebo instance pomocí funkceobjc_msgSend
.
pro více informací o zprávách v Objective-C se podívejte na práci Apple s Objectsguide.
příklad
Předpokládejme, že chcete vyvolat voličsizeWithFont:forWidth:lineBreakMode:
na NSString
.Prohlášení (z dokumentace společnosti Apple) je:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
toto API má následující vlastnosti:
- typ návratu je
CGSize
pro Unified API. - parametr
font
je uifont (a typ (nepřímo) odvozený z NSObject a je mapován do systému.Inttr. - parametr
width
, aCGFloat
, je mapován nanfloat
. - parametr
lineBreakMode
, aUILineBreakMode
, byl již vázán v Xamarinu.iOS jakoUILineBreakMode
výčet.
když to všechno spojíme, prohlášení objc_msgSend
by se mělo shodovat:
CGSize objc_msgSend( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
deklarujte to takto:
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int ( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
Chcete-li volat tuto metodu, použijte kód, jako je následující:
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);
kdyby vrácená hodnota byla struktura menší než 8 bajtů (jako starší SizeF
použitý před přepnutím na Unified API), výše uvedený kód by běžel na simulátoru, ale havaroval na zařízení. Chcete-li volat volič, který vrací hodnotu menší než 8 bitů, deklarujte funkci 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);
Chcete-li volat tuto metodu, použijte kód, jako je následující:
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 );
vyvolání voliče
vyvolání voliče má tři kroky:
- získejte cíl voliče.
- získejte název selektoru.
- volejte
objc_msgSend
s příslušnými argumenty.
selektivní cíle
cíl voliče je buď instance objektu, nebo třída Objective-C. Ifthe target je instance a pochází z vázaného Xamarinu.typ iOS, použijte vlastnost ObjCRuntime.INativeObject.Handle
.
pokud je cílem třída, použijte ObjCRuntime.Class
pro získání odkazu na classinstance, pak použijte vlastnost Class.Handle
.
Názvy selektorů
Názvy selektorů jsou uvedeny v dokumentaci společnosti Apple. Například NSString
zahrnuje selektory sizeWithFont:
a sizeWithFont:forWidth:lineBreakMode:
. Vložené a koncové dvojtečky jsou součástí názvu voliče a nelze je vynechat.
jakmile máte název selektoru, můžete pro něj vytvořit instanci ObjCRuntime.Selector
.
volání objc_msgSend
objc_msgSend
odešle zprávu (selektor) objektu. Tato rodina offunctions má alespoň dva požadované argumenty: cíl voliče (aninstance nebo třída handle), volič sám, a všechny arguments required pro voliče. Argumenty instance a voliče musí býtSystem.IntPtr
a všechny zbývající argumenty musí odpovídat typu, který theselector očekává, například nint
pro int
neboSystem.IntPtr
pro všechny NSObject
odvozené typy. Pomocí vlastnostiNSObject.Handle
získáte IntPtr
pro instanci typu Objective-C.
existuje více než jedna funkce objc_msgSend
:
- použijte
objc_msgSend_stret
pro selektory, které vracejí strukturu. Na ARM, to zahrnuje všechny returntypy, které nejsou výčtem ani žádným z vestavěných typů C(char
,short
,int
,long
,float
,double
). Na x86 (simulátor) musí být tato metoda použita pro všechny struktury větší než 8 bajtů (CGSize
je 8 bajtů a nepoužíváobjc_msgSend_stret
v simulátoru). - použijte
objc_msgSend_fpret
pro selektory, které vrátí hodnotu s pohyblivou řádovou čárkou pouze na x86. Tato funkce nemusí být použita na ARM; místo toho použijteobjc_msgSend
. - funkce mainobjc_msgSendfunction se používá pro všechny ostatní selektory.
jakmile se rozhodnete, které funkce objc_msgSend
musíte volat (simulátor a zařízení mohou vyžadovat jinou metodu), můžete použít normální metodu k deklaraci funkce pro pozdější vyvolání.
soubor předem připravených objc_msgSend
deklarací lze nalézt vObjCRuntime.Messaging
.
různé vyvolání na simulátoru a zařízení
jak je popsáno výše, Objective-C má tři druhy objc_msgSend
metod: jeden pro pravidelné vyvolání, jeden pro vyvolání, které vrací bodové hodnoty (pouze x86), a jeden pro vyvolání, které vrací hodnoty. Ten obsahuje příponu _stret
vObjCRuntime.Messaging
.
pokud vyvoláváte metodu, která vrátí určité struktury (pravidla popsaná níže), musíte metodu vyvolat s návratovou hodnotou jako firstparameter jako hodnotou 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);
pravidlo pro použití metody _stret_
se liší u x86 a ARM.Pokud chcete, aby vaše vazby fungovaly jak na simulátoru, tak na zařízení, přidejte kód, například následující:
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);}
použití metody objc_msgSend_stret
při vytváření pro ARM použijteobjc_msgSend_stret
pro jakýkoli typ hodnoty, který není výčtem nebo žádným základním typempro výčet (int
, byte
, short
, long
, double
, float
).
při stavbě pro x86 použijteobjc_msgSend_stret
pro jakýkoli typ hodnoty, který není výčtem nebo žádným základním typempro výčet (int
, byte
, short
, long
, double
, float
)a jehož nativní velikost je větší než 8 bajtů.
vytvoření vlastních podpisů
následující podstata může být použita k vytvoření vlastních podpisů, pokud je to nutné.