selektory Objective-C w Xamarin.iOS

  • 07/12/2017
  • 4 protokół do czytania
    • d
    • d
    • c
    • a

język Objective-C oparty jest na selektorach. Selektor jest wiadomością, którą można wysłać do obiektu lub klasy. Xamarin.iOS mapuje metody instancji selektorów do metod instancji, a selektory klas do metod statycznych.

w przeciwieństwie do zwykłych funkcji C (i jak funkcje składowe c++), nie można bezpośrednio wywoływać selektora używając P/Invoke,selektory są wysyłane do klasy lub instancji Objective-C za pomocą funkcjiobjc_msgSend.

aby uzyskać więcej informacji na temat komunikatów w Objective-C, spójrz na Apple ’ s working with Objectsguide.

przykład

Załóżmy, że chcesz wywołać selektor sizeWithFont:forWidth:lineBreakMode: na NSString.Deklaracja (z dokumentacji Apple) jest:

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

to API ma następujące cechy:

  • typ zwracany to CGSize dla ujednoliconego API.
  • parametr font jest UIFont (i typem (pośrednio) pochodzącym z NSObject i jest mapowany do systemu.IntPtr.
  • parametr width, a CGFloat, jest odwzorowany na nfloat.
  • parametr lineBreakMode, a UILineBreakMode,został już związany w Xamarin.iOS jako wyliczenieUILineBreakMode.

składając to wszystko, deklaracja objc_msgSend powinna pasować:

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

Zadeklaruj to w następujący sposób:

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 następujący:

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 zwracana wartość była strukturą o rozmiarze mniejszym niż 8 bajtów (jak starsza SizeF używana przed przejściem na ujednolicone interfejsy API), powyższy kod uruchomi się na symulatorze, ale zawiesi się na urządzeniu. Aby wywołać selektor, który zwraca wartość mniejszą niż 8 bitów, zadeklaruj funkcję 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 następujący:

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łanie selektora

wywołanie selektora składa się z trzech kroków:

  1. namierz cel.
  2. Pobierz nazwę selektora.
  3. wywołaj objc_msgSend z odpowiednimi argumentami.

obiekty docelowe selektora

obiekt docelowy selektora jest instancją obiektu lub klasą Objective-C. Ifthe target jest instancją i pochodzi z powiązanego Xamarin.wpisz iOS, użyj właściwości ObjCRuntime.INativeObject.Handle.

jeśli obiekt docelowy jest klasą, użyj ObjCRuntime.Class, aby uzyskać odniesienie do classinstance, a następnie użyj właściwości Class.Handle.

nazwy selektorów

nazwy selektorów są wymienione w dokumentacji Apple. Na przykład NSString zawiera selektory sizeWithFont: i sizeWithFont:forWidth:lineBreakMode:. Osadzone i końcowe dwukropki są częścią nazwy selektora i nie można ich pominąć.

gdy masz nazwę selektora, możesz utworzyć dla niego instancję ObjCRuntime.Selector.

wywołanie objc_msgSend

objc_msgSend wysyła wiadomość (selektor) do obiektu. Ta rodzina funkcji pobiera co najmniej dwa wymagane argumenty: cel selektora (aninstance lub class handle), sam Selektor i wszelkie wymagane argumenty dla selektora. Argumenty instancji i selektora muszą byćSystem.IntPtr, a wszystkie pozostałe argumenty muszą pasować do typu, którego oczekuje theselector, na przykład nint dla int lubSystem.IntPtrdla wszystkich typów pochodnych NSObject. Użyj właściwościNSObject.Handle, aby uzyskać IntPtr dla instancji typu Objective-C.

istnieje więcej niż jedna funkcja objc_msgSend :

  • użyj objc_msgSend_stretdla selektorów, które zwracają strukturę. Na ARM, obejmuje to wszystkie typy zwrotów, które nie są wyliczeniem ani żadnym z wbudowanych typów C(char,short, int, long, float, double). Na x86 (symulatorze), tismethod musi być użyty dla wszystkich struktur większych niż 8 bajtów (CGSize ma 8 bajtów i nie używa objc_msgSend_stret w symulatorze).
  • użyj objc_msgSend_fpretdla selektorów, które zwracają wartość zmiennoprzecinkową tylko dla x86. Ta funkcja nie musi być używana na ARM; zamiast tego użyj objc_msgSend.
  • mainobjc_msgSendfunction jest używana dla wszystkich innych selektorów.

gdy już zdecydujesz, które funkcje objc_msgSendmusisz wywołać(symulator i urządzenie mogą wymagać innej metody), możesz użyć normalnej metody , aby zadeklarować funkcję do późniejszego wywołania.

zestaw gotowych deklaracji objc_msgSendznajduje się wObjCRuntime.Messaging.

różne wywołania na symulatorze i urządzeniu

jak opisano powyżej, Objective-C ma trzy rodzaje metod objc_msgSend: jedną dla wywołań regularnych, jedną dla wywołań zwracających wartości punktów (tylko x86) i jedną dla wywołań zwracających wartości. Ten ostatni zawiera przyrostek _stret w ObjCRuntime.Messaging.

jeśli wywołujesz metodę, która zwróci określone struktury (reguły opisane poniżej), musisz wywołać metodę z wartością zwracaną jako wartość firstparameter jako wartość 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);

reguła dotycząca użycia metody _stret_ różni się w przypadku x86 i ARM.Jeśli chcesz,aby wiązania działały zarówno na symulatorze, jak i na urządzeniu, Dodaj następujący kod:

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żywając metody objc_msgSend_stret

podczas budowania dla ARM, użyjobjc_msgSend_stret dla dowolnego typu wartości, który nie jest wyliczeniem ani żadnym z typów bazowych dla wyliczenia (int, byte, short, long, double, float).

podczas budowania dla x86, użyjobjc_msgSend_stret dla dowolnego typu wartości, który nie jest wyliczeniem ani żadnym z typów bazowych dla wyliczenia (int, byte, short, long, double, float)i których natywny rozmiar jest większy niż 8 bajtów.

tworzenie własnych podpisów

poniższy gist może być użyty do utworzenia własnych podpisów, jeśli jest to wymagane.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.