Objective-C-Selektoren in Xamarin.iOS

  • 07/12/2017
  • 4 minuten zum Lesen
    • d
    • d
    • c
    • ein

Die Objective-C-Sprache basiert auf Selektoren. Ein Selektor ist eine Nachricht, die an ein Objekt oder eine Klasse gesendet werden kann. Xamarin.iOS ordnet Instanzselektoren Instanzmethoden und Klassenselektoren statischen Methoden zu.

Im Gegensatz zu normalen C-Funktionen (und wie C ++ – Memberfunktionen) können Sie einen Selektor nicht direkt mit P/Invoke aufrufen. Stattdessen werden Selektoren mit der Funktionobjc_msgSend an eine Objective-C-Klasse oder -Instanz gesendet.

Weitere Informationen zu Nachrichten in Objective-C finden Sie unter Arbeiten mit Objectsguide von Apple.

Beispiel

Angenommen, Sie möchten den SelektorsizeWithFont:forWidth:lineBreakMode: auf NSString aufrufen.Die Deklaration (aus der Dokumentation von Apple) lautet:

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

Diese API hat die folgenden Eigenschaften:

  • Der Rückgabetyp ist CGSize für die Unified API.
  • Der Parameter font ist ein UIFont (und ein (indirekt) von NSObject abgeleiteter Typ) und wird System zugeordnet.In: IntPtr.
  • Der Parameter width, a CGFloat, wird nfloat zugeordnet.
  • Der Parameter lineBreakMode, a UILineBreakMode , wurde bereits in Xamarin gebunden.iOS alsUILineBreakModeAufzählung.

Wenn Sie alles zusammenfassen, sollte die Deklaration objc_msgSend übereinstimmen:

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

Deklarieren Sie es wie folgt:

static extern CGSize cgsize_objc_msgSend_IntPtr_float_int ( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);

Verwenden Sie zum Aufrufen dieser Methode Code wie den folgenden:

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

Wäre der zurückgegebene Wert eine Struktur mit einer Größe von weniger als 8 Byte gewesen (wie das ältere SizeF, das vor dem Wechsel zu den Unified APIs verwendet wurde), wäre der obige Code auf dem Simulator ausgeführt worden, aber auf dem Gerät abgestürzt. Deklarieren Sie die Funktion objc_msgSend_stret, um einen Selektor aufzurufen, der einen Wert mit einer Größe von weniger als 8 Bit zurückgibt:

static extern void cgsize_objc_msgSend_stret_IntPtr_float_int ( out CGSize retval, IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);

Verwenden Sie zum Aufrufen dieser Methode Code wie den folgenden:

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

Aufrufen eines Selektors

Das Aufrufen eines Selektors besteht aus drei Schritten:

  1. Holen Sie sich das Selektorziel.
  2. Ruft den Selektornamen ab.
  3. Rufen Sie objc_msgSend mit den entsprechenden Argumenten auf.

Selektorziele

Ein Selektorziel ist entweder eine Objektinstanz oder eine Objective-C-Klasse. Ifthe Ziel ist eine Instanz und kam von einem gebundenen Xamarin.Verwenden Sie zum Eingeben die Eigenschaft ObjCRuntime.INativeObject.Handle.

Wenn das Ziel eine Klasse ist, verwenden Sie ObjCRuntime.Class, um einen Verweis auf die Klasseninstanz abzurufen, und verwenden Sie dann die Eigenschaft Class.Handle.

Selektornamen

Selektornamen sind in der Dokumentation von Apple aufgeführt. Beispiel: NSString enthält die Selektoren sizeWithFont: und sizeWithFont:forWidth:lineBreakMode:. Die eingebetteten und abschließenden Doppelpunkte sind Teil des Selektornamens und können nicht weggelassen werden.

Sobald Sie einen Selektornamen haben, können Sie eine ObjCRuntime.Selector Instanz dafür erstellen.

Der Aufruf von objc_msgSend

objc_msgSend sendet eine Nachricht (Selektor) an ein Objekt. Diese Familie offunctions benötigt mindestens zwei erforderliche Argumente: das Selektorziel (eine Instanz oder ein Klassenhandle), den Selektor selbst und alle Argumente, die für den Selektor erforderlich sind. Die Instanz- und Selektorargumente müssen System.IntPtr sein, und alle verbleibenden Argumente müssen mit dem von theselector erwarteten Typ übereinstimmen, z. B. nint für int oder System.IntPtr für alle von NSObject abgeleiteten Typen. Verwenden Sie die EigenschaftNSObject.Handle, um eine IntPtr für eine Objective-C-Instanz abzurufen.

Es gibt mehr als eine objc_msgSend Funktion:

  • Verwenden Sie objc_msgSend_stretfür Selektoren, die eine Struktur zurückgeben. Unter ARM umfasst dies alle returntypes, die keine Aufzählung oder einen der in C integrierten Typen sind (char,short, int, long, float, double). Auf x86 (dem Simulator) muss diese Methode für alle Strukturen verwendet werden, die größer als 8 Byte sind (CGSize ist 8 Byte und verwendet objc_msgSend_stret im Simulator nicht).
  • Verwenden Sie objc_msgSend_fpretfür Selektoren, die nur auf x86 einen Gleitkommawert zurückgeben. Thisfunction muss nicht auf ARM verwendet werden; Verwenden Sie stattdessen objc_msgSend .
  • Die mainobjc_msgSendfunction wird für alle anderen Selektoren verwendet.

Sobald Sie entschieden haben, welche objc_msgSend -Funktion (en) Sie aufrufen müssen (Simulator und Gerät erfordern möglicherweise jeweils eine andere Methode), können Sie eine normale -Methode verwenden, um die Funktion für einen späteren Aufruf zu deklarieren.

Eine Reihe vorgefertigter objc_msgSend -Deklarationen finden Sie inObjCRuntime.Messaging .

Verschiedene Aufrufe auf Simulator und Gerät

Wie oben beschrieben, verfügt Objective-C über drei Arten von objc_msgSend -Methoden: eine für reguläre Aufrufe, eine für Aufrufe, die Floating-Point-Werte zurückgeben (nur x86), und eine für Aufrufe, die returnstruct-Werte zurückgeben. Letzteres enthält das Suffix _stret inObjCRuntime.Messaging.

Wenn Sie eine Methode aufrufen, die bestimmte Strukturen zurückgibt (rulesdescribed below ), müssen Sie die Methode mit dem Rückgabewert als firstparameter als out -Wert aufrufen:

// The following returns a PointF structure:PointF ret;Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);

Die Regel für die Verwendung der _stret_ -Methode unterscheidet sich auf x86 und ARM.Wenn Sie möchten, dass Ihre Bindungen sowohl auf dem Simulator als auch auf dem Gerät funktionieren,fügen Sie Code wie den folgenden hinzu:

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

Verwenden der Methode objc_msgSend_stret

Verwenden Sie beim Erstellen für ARMobjc_msgSend_stretfür jeden Werttyp, der keine Aufzählung ist, oder einen der Basistypen für eine Aufzählung (int, byte, short, long, double, float).

Verwenden Sie beim Erstellen für x86objc_msgSend_stretfür jeden Werttyp, der keine Aufzählung ist, oder einen der Basistypen für eine Aufzählung (int, byte, short, long, double, float) und deren native Größe größer als 8 Bytes ist.

Eigene Signaturen erstellen

Mit dem folgenden Gist können Sie bei Bedarf eigene Signaturen erstellen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.