Objective-C selektory v Xamarin.iOS
Jazyk Objective-C je založený na selektorech. Selektor je zpráva, která se dá odeslat do objektu nebo třídy. Xamarin.iOS mapuje selektory instancí na metody instancí a selektory tříd na statické metody.
Na rozdíl od normálních funkcí jazyka C (a podobně jako členské funkce jazyka C++) nelze přímo vyvolat selektor pomocí volání nespravovaného volání, selektory se odesílají do Objective-C třídy nebo instance pomocíobjc_msgSend
Funkce.
Další informace o zprávách najdete Objective-Cv příručce Práce s objekty společnosti Apple.
Příklad
Předpokládejme, že chcete vyvolat sizeWithFont:forWidth:lineBreakMode:
selektor zapnutý NSString
.
Deklarace (z dokumentace společnosti Apple) je:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Toto rozhraní API má následující charakteristiky:
- Návratový typ je
CGSize
určený pro sjednocené rozhraní API. - Parametr
font
je UIFont (a typ (nepřímo) odvozený z NSObject a je mapován na System.IntPtr. - Parametr
width
, aCGFloat
, je namapován nanfloat
. - Parametr
lineBreakMode
, aUILineBreakMode
, již byl vázán v Xamarin.iOS jakoUILineBreakMode
Výčtu.
Všechny deklarace by se měly shodovat objc_msgSend
:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Deklarujte ji následujícím způsobem:
[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 volat tuto metodu, použijte kód, například 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
);
Byla-li vrácená hodnota strukturou menší než 8 bajtů (podobně jako starší SizeF
použitá před přepnutím na sjednocená rozhraní API), výše uvedený kód by běžel na simulátoru, ale v zařízení došlo k chybovému ukončení. Chcete-li volat selektor, který vrátí hodnotu menší než 8 bitů velikosti, deklarujte objc_msgSend_stret
funkci:
[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 volat tuto metodu, použijte kód, například 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í selektoru
Vyvolání selektoru má tři kroky:
- Získejte cíl selektoru.
- Získejte název selektoru.
- Volání
objc_msgSend
s příslušnými argumenty
Cíle selektoru
Cíl selektoru je buď instance objektu Objective-C , nebo třída. Pokud je cílem instance a pochází z vázaného typu Xamarin.iOS, použijte ObjCRuntime.INativeObject.Handle
vlastnost.
Pokud je cílem třída, použijte ObjCRuntime.Class
k získání odkazu na instanci třídy a pak použijte Class.Handle
vlastnost.
Názvy selektorů
Názvy selektorů jsou uvedené v dokumentaci společnosti Apple. Zahrnuje například NSString
sizeWithFont:
a sizeWithFont:forWidth:lineBreakMode:
selektory. Vložené a koncové dvojtečky jsou součástí názvu selektoru a nelze je vynechat.
Jakmile budete mít název selektoru, můžete pro něj vytvořit ObjCRuntime.Selector
instanci.
Volání objc_msgSend
objc_msgSend
odešle zprávu (selektor) objektu. Tato řada funkcí má alespoň dva požadované argumenty: cíl selektoru (instance nebo popisovač třídy), samotný selektor a všechny argumenty požadované pro selektor. Argumenty instance a selektoru musí být System.IntPtr
a všechny zbývající argumenty musí odpovídat typu, který selektor očekává, například nint
pro int
System.IntPtr
nebo pro všechny NSObject
odvozené typy. Použít NSObject.Handle
vlastnost k získání IntPtr
instance Objective-C typu.
Existuje více než jedna objc_msgSend
funkce:
- Slouží
objc_msgSend_stret
pro selektory, které vrací strukturu. V ARM to zahrnuje všechny návratové typy, které nejsou výčtem nebo žádným z předdefinovaných typů jazyka C (char
, ,short
int
,long
,float
, ).double
V x86 (simulátoru) musí být tato metoda použita pro všechny struktury větší než 8 bajtů velikosti (CGSize
je 8 bajtů a nepoužíváobjc_msgSend_stret
se v simulátoru). - Slouží
objc_msgSend_fpret
pouze pro selektory, které vracejí hodnotu s plovoucí desetinou čárkou pouze u x86. Tuto funkci není nutné používat v ARM; místo toho použijteobjc_msgSend
. - Hlavní objc_msgSend funkce se používá pro všechny ostatní selektory.
Jakmile se rozhodnete, které objc_msgSend
funkce potřebujete volat (simulátor a zařízení můžou vyžadovat jinou metodu), můžete pomocí normální [DllImport]
metody deklarovat funkci pro pozdější vyvolání.
Soubor předpřipravených objc_msgSend
deklarací lze nalézt v ObjCRuntime.Messaging
části .
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é vracejí hodnoty s plovoucí desetinou čárkou (pouze x86) a jeden pro vyvolání, které vracejí hodnoty struktury. Druhá zahrnuje příponu _stret
v ObjCRuntime.Messaging
.
Pokud voláte metodu, která vrátí určité struktury (pravidla popsaná níže), musíte metodu vyvolat s návratovou out
hodnotou jako první parametr jako hodnotu:
// 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, kdy použít metodu _stret_
, se liší v x86 a ARM.
Pokud chcete, aby vazby fungovaly na simulátoru i 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 sestavování pro ARM použijte objc_msgSend_stret
pro libovolný typ hodnoty, který není výčtem nebo žádným ze základních typů výčtu (int
, byte
, , long
short
, double
). float
Při sestavování pro x86 použijte objc_msgSend_stret
pro libovolný typ hodnoty, který není výčtem nebo žádným ze základních typů výčtu (int
, , , long
short
, ) double
float
a jehož nativní velikost je větší než 8 byte
bajtů.
Vytváření vlastních podpisů
V případě potřeby můžete k vytvoření vlastních podpisů použít následující gist .