Objective-C selektory w środowisku Xamarin.iOS
Język Objective-C jest oparty na selektorach. Selektor to komunikat, który można wysłać do obiektu lub klasy. Selektory wystąpień platformy Xamarin.iOS mapuje na metody wystąpienia, a selektory klas do metod statycznych.
W przeciwieństwie do normalnych funkcji języka C (i takich jak funkcje składowe języka C++) nie można bezpośrednio wywołać selektora przy użyciu funkcji P/Invoke, selektory są wysyłane do Objective-C klasy lub wystąpienia przy użyciu elementuobjc_msgSend
Funkcja.
Aby uzyskać więcej informacji na temat komunikatów w programie Objective-C, zapoznaj się z przewodnikiem Apple Working with Objects (Praca z obiektami firmy Apple).
Przykład
Załóżmy, że chcesz wywołać element sizeWithFont:forWidth:lineBreakMode:
selektor na .NSString
Deklaracja (z dokumentacji firmy Apple) to:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Ten interfejs API ma następujące cechy:
- Zwracany typ jest
CGSize
przeznaczony dla ujednoliconego interfejsu API. - Parametr
font
jest interfejsem UIFont (i typem (pośrednio) pochodzącym z obiektu NSObject i jest mapowany na System.IntPtr. - Parametr
width
,CGFloat
jest mapowany nanfloat
. - Parametr
lineBreakMode
,UILineBreakMode
został już powiązany w środowisku Xamarin.iOS jakoUILineBreakMode
Wyliczenie.
Łącząc to wszystko, deklaracja powinna być zgodna objc_msgSend
z następującymi elementami:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Zadeklaruj je w następujący sposób:
[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
);
Aby wywołać tę metodę, użyj kodu, takiego jak:
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
);
Gdyby zwrócona wartość była strukturą o rozmiarze mniejszym niż 8 bajtów (na przykład starszym SizeF
używanym przed przełączeniem do ujednoliconych interfejsów API), powyższy kod zostałby uruchomiony na symulatorze, ale uległby awarii na urządzeniu. Aby wywołać selektor, który zwraca wartość mniejszą niż 8 bitów rozmiaru, zadeklaruj objc_msgSend_stret
funkcję:
[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
);
Aby wywołać tę metodę, użyj kodu, takiego jak:
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
);
Wywoływanie selektora
Wywoływanie selektora obejmuje trzy kroki:
- Pobierz element docelowy selektora.
- Pobierz nazwę selektora.
- Wywołaj
objc_msgSend
metodę przy użyciu odpowiednich argumentów.
Cele selektora
Obiekt docelowy selektora jest wystąpieniem obiektu lub klasą Objective-C . Jeśli elementem docelowym jest wystąpienie i pochodzi z powiązanego typu Xamarin.iOS, użyj ObjCRuntime.INativeObject.Handle
właściwości .
Jeśli element docelowy jest klasą, użyj polecenia ObjCRuntime.Class
, aby uzyskać odwołanie do wystąpienia klasy, a następnie użyj Class.Handle
właściwości .
Nazwy selektorów
Nazwy selektorów są wymienione w dokumentacji firmy Apple. Na przykład NSString
zawiera sizeWithFont:
selektory i sizeWithFont:forWidth:lineBreakMode:
selektory. Osadzone i końcowe dwukropki są częścią nazwy selektora i nie można ich pominąć.
Po utworzeniu nazwy selektora ObjCRuntime.Selector
możesz utworzyć dla niego wystąpienie.
Wywoływanie objc_msgSend
objc_msgSend
wysyła komunikat (selektor) do obiektu. Ta rodzina funkcji przyjmuje co najmniej dwa wymagane argumenty: cel selektora (uchwyt wystąpienia lub klasy), selektor sam i wszystkie argumenty wymagane dla selektora. Argumenty wystąpienia i selektora muszą mieć System.IntPtr
wartość , a wszystkie pozostałe argumenty muszą odpowiadać typowi oczekiwanego selektora, na przykład nint
dla int
elementu lub System.IntPtr
dla wszystkich NSObject
typów pochodnych. Użyj interfejsu NSObject.Handle
właściwość do uzyskania IntPtr
dla Objective-C wystąpienia typu.
Istnieje więcej niż jedna objc_msgSend
funkcja:
- Użyj
objc_msgSend_stret
dla selektorów, które zwracają strukturę. W usłudze ARM obejmuje to wszystkie typy zwracane, które nie są wyliczaniem ani żadnymi typami wbudowanymi języka C (, , ,long
int
,double
float
).short
char
W przypadku architektury x86 (symulatora) ta metoda musi być używana dla wszystkich struktur o rozmiarze większym niż 8 bajtów (CGSize
jest 8 bajtów i nie jest używanaobjc_msgSend_stret
w symulatorze). - Użyj
objc_msgSend_fpret
dla selektorów, które zwracają wartość zmiennoprzecinkową tylko na x86. Ta funkcja nie musi być używana w usłudze ARM; Zamiast tego użyj poleceniaobjc_msgSend
. - Główna funkcja objc_msgSend jest używana dla wszystkich innych selektorów.
Po podjęciu decyzji, które objc_msgSend
funkcje należy wywołać (symulator i urządzenie mogą wymagać innej metody), możesz użyć normalnej [DllImport]
metody, aby zadeklarować funkcję do późniejszego wywołania.
Zestaw wstępnie wykonanych objc_msgSend
deklaracji można znaleźć w pliku ObjCRuntime.Messaging
.
Różne wywołania w symulatorze i urządzeniu
Jak opisano powyżej, Objective-C ma trzy rodzaje objc_msgSend
metod: jeden dla zwykłych wywołań, jeden dla wywołań, które zwracają wartości zmiennoprzecinkowe (tylko x86) i jeden dla wywołań, które zwracają wartości struktury. Ten ostatni zawiera sufiks _stret
w pliku ObjCRuntime.Messaging
.
Jeśli wywołujesz metodę, która zwróci niektóre struktury (opisane poniżej reguły), musisz wywołać metodę z wartością zwracaną out
jako pierwszy parametr jako wartość:
// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
Reguła dotycząca tego, kiedy należy używać _stret_
metody, różni się w przypadku architektury x86 i arm.
Jeśli chcesz, aby powiązania działały zarówno na symulatorze, jak i na urządzeniu, dodaj kod, taki jak:
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);
}
Używanie metody objc_msgSend_stret
Podczas kompilowania dla usługi ARM użyj polecenia objc_msgSend_stret
dla dowolnego typu wartości, który nie jest wyliczeniem ani żadnym z typów bazowych dla wyliczenia (int
, byte
, , long
short
, double
, float
).
Podczas kompilowania dla architektury x86 użyj polecenia objc_msgSend_stret
dla dowolnego typu wartości, który nie jest wyliczeniem lub żadnym z typów podstawowych dla wyliczenia (int
, byte
, , long
short
, double
, float
) i którego rozmiar natywny jest większy niż 8 bajtów.
Tworzenie własnych podpisów
Poniższy element może służyć do tworzenia własnych podpisów, jeśli jest to wymagane.