Objective-C Selektoren in Xamarin.iOS
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 instance Selektoren instance Methoden 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. Selektoren werden stattdessen mithilfe von an eine Objective-C Klasse oder instance gesendet.objc_msgSend
Funktion.
Weitere Informationen zu Nachrichten in finden Sie im Objective-CLeitfaden arbeiten mit Objekten von Apple.
Beispiel
Angenommen, Sie möchten diesizeWithFont:forWidth:lineBreakMode:
-Auswahl auf NSString
.
Die Erklärung (aus der Apple-Dokumentation) lautet:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Diese API weist die folgenden Merkmale auf:
- Der Rückgabetyp ist
CGSize
für die einheitliche API. - Der
font
Parameter ist ein UIFont (und ein (indirekt) von NSObject abgeleiteter Typ und wird System.IntPtr zugeordnet. - Der
width
-Parameter wirdCGFloat
zugeordnetnfloat
. - Der
lineBreakMode
-Parameter wurdeUILineBreakMode
bereits in Xamarin.iOS als gebunden.UILineBreakMode
Enumeration.
Die Deklaration sollte zusammen mit folgenden objc_msgSend
Übereinstimmungen übereinstimmen:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Deklarieren Sie sie wie folgt:
[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
);
Verwenden Sie code wie den folgenden, um diese Methode aufzurufen:
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 von weniger als 8 Bytes groß (wie die ältere SizeF
, die vor dem Wechsel zu den einheitlichen APIs verwendet wurde), wäre der obige Code im Simulator ausgeführt worden, aber auf dem Gerät abgestürzt. Um einen Selektor aufzurufen, der einen Wert zurückgibt, der weniger als 8 Bits groß ist, deklarieren Sie die objc_msgSend_stret
Funktion:
[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
);
Verwenden Sie code wie den folgenden, um diese Methode aufzurufen:
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 umfasst drei Schritte:
- Rufen Sie das Selektorziel ab.
- Rufen Sie den Selektornamen ab.
- Rufen Sie
objc_msgSend
mit den entsprechenden Argumenten auf.
Selektorziele
Ein Selektorziel ist entweder ein Objekt instance oder eine Objective-C Klasse. Wenn das Ziel ein instance ist und von einem gebundenen Xamarin.iOS-Typ stammt, verwenden Sie die ObjCRuntime.INativeObject.Handle
-Eigenschaft.
Wenn das Ziel eine Klasse ist, verwenden Sie ObjCRuntime.Class
, um einen Verweis auf die Klasse instance abzurufen, und verwenden Sie dann die Class.Handle
-Eigenschaft.
Selektornamen
Selektornamen sind in der Apple-Dokumentation aufgeführt. Enthält sizeWithFont:
z. NSString
B. und sizeWithFont:forWidth:lineBreakMode:
Selektoren. Die eingebetteten und nachfolgenden Doppelpunkte sind Teil des Selektornamens und können nicht weggelassen werden.
Sobald Sie über einen Selektornamen verfügen, können Sie eine ObjCRuntime.Selector
instance dafür erstellen.
Aufrufen von objc_msgSend
objc_msgSend
sendet eine Nachricht (Selektor) an ein -Objekt. Diese Funktionsfamilie akzeptiert mindestens zwei erforderliche Argumente: das Selektorziel (ein instance- oder Klassenhandle), den Selektor selbst und alle argumente, die für den Selektor erforderlich sind. Die argumente instance und selektor müssen seinSystem.IntPtr
, und alle verbleibenden Argumente müssen mit dem Typ übereinstimmen, den der Selektor erwartet, z. B. ein nint
für ein int
oder ein System.IntPtr
für alle NSObject
abgeleiteten Typen. Verwenden Sie die SchaltflächeNSObject.Handle
-Eigenschaft zum Abrufen eines IntPtr
für einen Objective-C Typ instance.
Es gibt mehrere objc_msgSend
Funktionen:
- Verwenden Sie
objc_msgSend_stret
für Selektoren, die eine Struktur zurückgeben. In ARM umfasst dies alle Rückgabetypen, die keine Enumeration sind, oder einen der integrierten C-Typen (char
, ,int
short
,long
float
, ,double
). Auf x86 (dem Simulator) muss diese Methode für alle Strukturen verwendet werden, die größer als 8 Bytes sind (CGSize
ist 8 Bytes und wird im Simulator nicht verwendetobjc_msgSend_stret
). - Verwenden Sie nur
objc_msgSend_fpret
für Selektoren, die einen Gleitkommawert für x86 zurückgeben. Diese Funktion muss nicht für ARM verwendet werden. Verwenden Sieobjc_msgSend
stattdessen . - Die Standard objc_msgSend-Funktion wird für alle anderen Selektoren verwendet.
Nachdem Sie entschieden haben, welche objc_msgSend
Funktionen Sie aufrufen müssen (Simulator und Gerät erfordern möglicherweise jeweils eine andere Methode), können Sie eine normale [DllImport]
Methode verwenden, um die Funktion für den späteren Aufruf zu deklarieren.
Eine Reihe von vordefinierten objc_msgSend
Deklarationen finden Sie in ObjCRuntime.Messaging
.
Verschiedene Aufrufe auf Simulator und Gerät
Wie oben beschrieben, Objective-C verfügt über drei Arten von objc_msgSend
Methoden: eine für reguläre Aufrufe, eine für Aufrufe, die Gleitkommawerte zurückgeben (nur x86), und eine für Aufrufe, die Strukturwerte zurückgeben. Letzteres enthält das Suffix _stret
in ObjCRuntime.Messaging
.
Wenn Sie eine Methode aufrufen, die bestimmte Strukturen (unten beschriebene Regeln) zurückgibt, müssen Sie die -Methode mit dem Rückgabewert als ersten Parameter als Wert out
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 bei x86 und ARM.
Wenn Ihre Bindungen sowohl auf dem Simulator als auch auf dem Gerät funktionieren sollen, 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 objc_msgSend_stret-Methode
Verwenden Sie beim Erstellen für ARM dieobjc_msgSend_stret
für jeden Werttyp, der keine Enumeration ist, oder einen der Basistypen für eine Enumeration (int
, , short
byte
, long
double
, , float
).
Verwenden Sie beim Erstellen für x86objc_msgSend_stret
für jeden Werttyp, der keine Enumeration ist, oder einen der Basistypen für eine Enumeration (int
, , short
byte
, long
, double
float
) und deren systemeigene Größe größer als 8 Byte ist.
Erstellen eigener Signaturen
Der folgende Gist kann verwendet werden, um bei Bedarf eigene Signaturen zu erstellen.