selektory Objective-C v Xamarinu.iOS

  • 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, a CGFloat, je mapován na nfloat.
  • parametr lineBreakMode, a UILineBreakMode, byl již vázán v Xamarinu.iOS jako UILineBreakModevýč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:

  1. získejte cíl voliče.
  2. získejte název selektoru.
  3. 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 NSObjectodvozené typy. Pomocí vlastnostiNSObject.Handlezískáte IntPtr pro instanci typu Objective-C.

existuje více než jedna funkce objc_msgSend :

  • použijte objc_msgSend_stretpro 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_fpretpro 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žijte objc_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_msgSendmetod: 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_stretpro 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_stretpro 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é.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.