Selektory s cíli a C v Xamarin. iOSObjective-C selectors in Xamarin.iOS

Jazyk cíl-C je založen na selektorech.The Objective-C language is based upon selectors. Selektor je zpráva, kterou lze odeslat do objektu nebo třídy.A selector is a message that can be sent to an object or a class. Xamarin. iOS mapuje selektory instancí na metody instance a selektory tříd do statických metod.Xamarin.iOS maps instance selectors to instance methods, and class selectors to static methods.

Na rozdíl od normálních funkcí jazyka C C++ (a jako členské funkce) nemůžete místo toho přímo vyvolat selektor pomocí volání nespravovaného volání. selektory se odesílají do třídy cíl-C nebo instance pomocí objc_msgSendUnlike normal C functions (and like C++ member functions), you cannot directly invoke a selector using P/Invoke Instead, selectors are sent to an Objective-C class or instance using the objc_msgSend slouží.function.

Pokud chcete získat další informace o zprávách v cíli – C, podívejte se na příručka práce s objekty od společnosti Apple.For more information about messages in Objective-C, take a look at Apple's Working with Objects guide.

PříkladExample

Předpokládejme, že chcete vyvolat sizeWithFont:forWidth:lineBreakMode:Suppose you want to invoke the sizeWithFont:forWidth:lineBreakMode: selektor na NSString.selector on NSString. Deklarace (z dokumentace od společnosti Apple) je:The declaration (from Apple's documentation) is:

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

Toto rozhraní API má následující vlastnosti:This API has the following characteristics:

  • Návratový typ je CGSize pro Unified API.The return type is CGSize for the Unified API.
  • Parametr font je UIFont (a typ (nepřímo) odvozený z nsobjectua je mapován na System. IntPtr.The font parameter is a UIFont (and a type (indirectly) derived from NSObject, and is mapped to System.IntPtr.
  • Parametr width, CGFloat, je namapován na nfloat.The width parameter, a CGFloat, is mapped to nfloat.
  • Parametr lineBreakMode, UILineBreakMode, již byl v Xamarin. iOS vázaný jako UILineBreakModeThe lineBreakMode parameter, a UILineBreakMode, has already been bound in Xamarin.iOS as the UILineBreakMode Enumeration.enumeration.

Pro všechny dohromady by deklarace objc_msgSend měla odpovídat:Putting it all together, the objc_msgSend declaration should match:

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

Deklarujte ho následujícím způsobem:Declare it as follows:

[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
);

Chcete-li zavolat tuto metodu, použijte následující kód:To call this method, use code such as the following:

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
);

Byla vrácená hodnota struktura, která byla menší než 8 bajtů (například starší SizeF používala před přepnutím na sjednocená rozhraní API), výše uvedený kód by byl spuštěn na simulátoru, ale v zařízení došlo k chybě.Had the returned value been a structure that was less than 8 bytes in size (like the older SizeF used before switching to the Unified APIs), the above code would have run on the simulator but crashed on the device. Chcete-li volat selektor, který vrací hodnotu menší než 8 bitů, Deklarujte funkci objc_msgSend_stret:To call a selector that returns a value less than 8 bits in size, declare the objc_msgSend_stret function:

[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
);

Chcete-li zavolat tuto metodu, použijte následující kód:To call this method, use code such as the following:

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í selektoruInvoking a selector

Vyvolání selektoru má tři kroky:Invoking a selector has three steps:

  1. Získá cíl selektoru.Get the selector target.
  2. Získá název selektoru.Get the selector name.
  3. Zavolejte objc_msgSend s příslušnými argumenty.Call objc_msgSend with the appropriate arguments.

Cíle selektoruSelector targets

Cílem selektoru je buď instance objektu, nebo třída Target-C.A selector target is either an object instance or an Objective-C class. Pokud je cílem instance a pochází z vázaného typu Xamarin. iOS, použijte vlastnost ObjCRuntime.INativeObject.Handle .If the target is an instance and came from a bound Xamarin.iOS type, use the ObjCRuntime.INativeObject.Handle property.

Pokud je cílem třída, pomocí ObjCRuntime.Class získat odkaz na instanci třídy, pak použijte vlastnost Class.Handle .If the target is a class, use ObjCRuntime.Class to get a reference to the class instance, then use the Class.Handle property.

Názvy selektorůSelector names

Názvy selektoru jsou uvedené v dokumentaci společnosti Apple.Selector names are listed in Apple's documentation. Například NSString zahrnuje selektory sizeWithFont: a sizeWithFont:forWidth:lineBreakMode: .For example, NSString includes sizeWithFont: and sizeWithFont:forWidth:lineBreakMode: selectors. Vložená a koncová dvojtečka jsou součástí názvu selektoru a nelze ji vynechat.The embedded and trailing colons are part of the selector name and cannot be omitted.

Jakmile budete mít název selektoru, můžete pro něj vytvořit instanci ObjCRuntime.Selector .Once you have a selector name, you can create a ObjCRuntime.Selector instance for it.

Volání objc_msgSendCalling objc_msgSend

objc_msgSend pošle zprávu (selektor) objektu.objc_msgSend sends a message (selector) to an object. Tato rodina funkcí přijímá alespoň dva povinné argumenty: cíl selektoru (popisovač instance nebo třídy), samotný selektor a všechny argumenty vyžadované pro selektor.This family of functions takes at least two required arguments: the selector target (an instance or class handle), the selector itself, and any arguments required for the selector. Argumenty instance a selektoru musí být System.IntPtra všechny zbývající argumenty se musí shodovat s typem, který selektor očekává, například nint pro intnebo System.IntPtr pro všechny typy odvozené od NSObject.The instance and selector arguments must be System.IntPtr, and all remaining arguments must match the type the selector expects, for example an nint for an int, or a System.IntPtr for all NSObject-derived types. Použití NSObject.HandleUse the NSObject.Handle vlastnost, která získá IntPtr pro instanci typu cíl-C.property to obtain an IntPtr for an Objective-C type instance.

Existuje více než jedna funkce objc_msgSend:There is more than one objc_msgSend function:

  • Použijte objc_msgSend_stret pro selektory, které vracejí strukturu.Use objc_msgSend_stret for selectors that return a struct. Na ARM to zahrnuje všechny návratové typy, které nejsou výčtem ani žádné předdefinované typy jazyka C (char, short, int, long, float, double).On ARM, this includes all return types that are not an enumeration or any of the C built-in types (char, short, int, long, float, double). Na platformě x86 (simulátor) je nutné tuto metodu použít pro všechny struktury větší než 8 bajtů (CGSize je 8 bajtů a objc_msgSend_stret v simulátoru nepoužívá).On x86 (the simulator), this method needs to be used for all structures larger than 8 bytes in size (CGSize is 8 bytes and doesn't use objc_msgSend_stret in the simulator).
  • Použijte objc_msgSend_fpret pro selektory, které vrací hodnotu s plovoucí desetinnou čárkou pouze v x86.Use objc_msgSend_fpret for selectors that return a floating point value on x86 only. Tuto funkci není nutné používat na ARM. místo toho použijte objc_msgSend.This function does not need to be used on ARM; instead, use objc_msgSend.
  • Funkce main objc_msgSend se používá pro všechny ostatní selektory.The main objc_msgSend function is used for all other selectors.

Jakmile se rozhodnete, které objc_msgSend funkce je třeba volat (simulátor a zařízení mohou vyžadovat jinou metodu), můžete použít normální metodu [DllImport] k deklaraci funkce pro pozdější vyvolání.Once you've decided which objc_msgSend function(s) you need to call (simulator and device may each require a different method), you can use a normal [DllImport] method to declare the function for later invocation.

Sadu předem připravených objc_msgSendch deklarací najdete v ObjCRuntime.Messaging.A set of pre-made objc_msgSend declarations can be found in ObjCRuntime.Messaging.

Různá volání simulátoru a zařízeníDifferent invocations on simulator and device

Jak je popsáno výše, cíl-C má tři druhy objc_msgSend metod: jedno pro pravidelná volání, jedno pro vyvolání, které vrací hodnoty s plovoucí desetinnou čárkou (pouze x86) a jedno pro vyvolání, které vrací hodnoty struktury.As described above, Objective-C has three kinds of objc_msgSend methods: one for regular invocations, one for invocations that return floating point values (x86 only), and one for invocations that return struct values. Ta zahrnuje příponu _stret v ObjCRuntime.Messaging.The latter includes the suffix _stret in ObjCRuntime.Messaging.

Pokud vyvoláte metodu, která bude vracet určité struktury (pravidla popsané níže), musíte vyvolat metodu s návratovou hodnotou jako první parametr jako outovou hodnotu:If you are invoking a method that will return certain structs (rules described below), you must invoke the method with the return value as the first parameter as an out value:

// 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ší v x86 a ARM.The rule for when to use the _stret_ method differs on x86 and ARM. Chcete-li, aby vazby pracovaly na simulátoru i na zařízení, přidejte kód jako následující:If you want your bindings to work on both the simulator and the device, add code such as the following:

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_stretUsing the objc_msgSend_stret method

Při sestavování pro ARM použijte objc_msgSend_stretWhen building for ARM, use the objc_msgSend_stret pro libovolný typ hodnoty, který není výčet ani žádný ze základních typů pro výčet (int, byte, short, long, double, float).for any value type that is not an enumeration or any of the base types for an enumeration (int, byte, short, long, double, float).

Při sestavování pro x86 použijte objc_msgSend_stretWhen building for x86, use objc_msgSend_stret pro libovolný typ hodnoty, který není výčet ani žádný ze základních typů pro výčet (int, byte, short, long, double, float) a jehož nativní velikost je větší než 8 bajtů.for any value type that is not an enumeration or any of the base types for an enumeration (int, byte, short, long, double, float) and whose native size is larger than 8 bytes.

Vytváření vlastních podpisůCreating your own signatures

V případě potřeby můžete vytvořit vlastní signatury pomocí následujícího registru .The following gist can be used to create your own signatures, if required.